Skip to content

Commit 4f9af88

Browse files
committed
make it reconnect at prev cursor
1 parent 3300683 commit 4f9af88

2 files changed

Lines changed: 33 additions & 28 deletions

File tree

src/LabelWatcher.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,18 @@ const run = Effect.gen(function* () {
1616
const connect = yield* RetryingSocket;
1717
const agent = yield* AtpListAccountAgent;
1818
const cursor = yield* Cursor;
19-
const initialCursor = yield* cursor.get;
2019
const { labelerSocketUrl } = yield* Env;
21-
labelerSocketUrl.searchParams.set("cursor", initialCursor.toString());
2220

23-
const stream = connect({ url: labelerSocketUrl });
21+
// Effect that builds URL with current cursor - re-evaluated on each reconnect
22+
const getUrl = Effect.gen(function* () {
23+
const currentCursor = yield* cursor.get;
24+
const url = new URL(labelerSocketUrl.toString());
25+
url.searchParams.set("cursor", currentCursor.toString());
26+
yield* Effect.log(`Building connection URL with cursor: ${currentCursor}`);
27+
return url;
28+
});
29+
30+
const stream = connect({ getUrl });
2431

2532
const runStream = stream.pipe(
2633
Stream.mapEffect(parseMessage),

src/RetryingSocket.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,49 @@
1-
import { Socket } from "@effect/platform"
2-
import type { SocketError } from "@effect/platform/Socket"
3-
import { Data, Effect, Schedule, Stream } from "effect"
1+
import { Socket } from "@effect/platform";
2+
import type { SocketError } from "@effect/platform/Socket";
3+
import { Cause, Effect, Schedule, Stream } from "effect";
44

55
/**
6-
* A stream that will reconnect to the websocket on error
6+
* A stream that will reconnect to the websocket on error.
7+
* Takes an Effect that produces the URL so it can re-evaluate
8+
* (e.g., get current cursor) on each reconnection attempt.
79
*/
8-
const wsStream = ({ url }: { url: string | URL }) =>
9-
Stream.asyncPush<Uint8Array<ArrayBufferLike>, SocketError>((emit) =>
10-
Effect.gen(function*() {
11-
yield* Effect.log("Connecting to websocket at: ", url.toString())
10+
const wsStream = <R>({ getUrl }: { getUrl: Effect.Effect<URL, never, R> }) =>
11+
Stream.asyncPush<Uint8Array<ArrayBufferLike>, SocketError, R>((emit) =>
12+
Effect.gen(function* () {
13+
const url = yield* getUrl;
14+
yield* Effect.log("Connecting to websocket at: ", url.toString());
1215
const socket = yield* Socket.makeWebSocket(url.toString(), {
1316
closeCodeIsError: (_) => true,
14-
})
17+
});
1518

1619
const e = socket
1720
.run((d) =>
18-
Effect.gen(function*() {
19-
const didEmit = emit.single(d)
21+
Effect.gen(function* () {
22+
const didEmit = emit.single(d);
2023
if (!didEmit) {
24+
// this doesn't seem to work because asyncPush uses an unbounded queue internally
25+
// and thus it only returns false when done.
2126
yield* new BufferOverflowError({
2227
message: "Socket buffer overflowed, failed to emit a message.",
23-
})
28+
});
2429
}
2530
})
2631
)
2732
.pipe(
2833
Effect.catchTag("SocketError", (e) => Effect.succeed(emit.fail(e))),
29-
Effect.fork,
30-
)
34+
Effect.fork
35+
);
3136

32-
yield* e
37+
yield* e;
3338
}).pipe(Effect.provide(Socket.layerWebSocketConstructorGlobal))
3439
).pipe(
3540
Stream.tapErrorCause(Effect.logError),
36-
Stream.retry(Schedule.spaced("1 second")),
37-
)
38-
39-
export class BufferOverflowError extends Data.TaggedError(
40-
"BufferOverflowError",
41-
)<{
42-
message: string
43-
cause?: unknown
44-
}> {}
41+
Stream.retry(Schedule.spaced("1 second"))
42+
);
4543

4644
export class RetryingSocket extends Effect.Service<RetryingSocket>()(
4745
"RetryingSocket",
4846
{
4947
succeed: wsStream,
50-
},
48+
}
5149
) {}

0 commit comments

Comments
 (0)