@livestore/webmesh 0.4.0-dev.12 → 0.4.0-dev.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/examples/reload-repro.d.ts +2 -0
- package/dist/examples/reload-repro.d.ts.map +1 -0
- package/dist/examples/reload-repro.js +136 -0
- package/dist/examples/reload-repro.js.map +1 -0
- package/dist/examples/starvation-repro-single-port.d.ts +2 -0
- package/dist/examples/starvation-repro-single-port.d.ts.map +1 -0
- package/dist/examples/starvation-repro-single-port.js +89 -0
- package/dist/examples/starvation-repro-single-port.js.map +1 -0
- package/dist/examples/starvation-repro.d.ts +2 -0
- package/dist/examples/starvation-repro.d.ts.map +1 -0
- package/dist/examples/starvation-repro.js +171 -0
- package/dist/examples/starvation-repro.js.map +1 -0
- package/dist/reload-handover.mesh.test.d.ts +2 -0
- package/dist/reload-handover.mesh.test.d.ts.map +1 -0
- package/dist/reload-handover.mesh.test.js +130 -0
- package/dist/reload-handover.mesh.test.js.map +1 -0
- package/dist/reload-reconnect.test.d.ts +2 -0
- package/dist/reload-reconnect.test.d.ts.map +1 -0
- package/dist/reload-reconnect.test.js +62 -0
- package/dist/reload-reconnect.test.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { MessageChannel } from 'node:worker_threads';
|
|
2
|
+
import { Effect, Schema, Stream, WebChannel } from '@livestore/utils/effect';
|
|
3
|
+
import { Vitest } from '@livestore/utils-dev/node-vitest';
|
|
4
|
+
import { expect } from 'vitest';
|
|
5
|
+
// This test encodes a minimal reload/reconnect scenario over a single MessagePort where
|
|
6
|
+
// one leader Pong is dropped exactly at the reload handover window. Today, DevTools
|
|
7
|
+
// observations show a single leader timeout near reload while clientSession pings continue
|
|
8
|
+
// to succeed. We assert the desired correct behavior (no timeout for leader), which currently
|
|
9
|
+
// FAILS, documenting the problem and providing a minimal repro target.
|
|
10
|
+
// NOTE: This test uses WebChannel directly (no Mesh) to isolate transport scheduling from Mesh logic.
|
|
11
|
+
// It simulates handover by deliberately dropping one leader Pong.
|
|
12
|
+
const Ping = Schema.TaggedStruct('Ping', { who: Schema.String, id: Schema.String, t0: Schema.Number });
|
|
13
|
+
const Pong = Schema.TaggedStruct('Pong', { who: Schema.String, id: Schema.String, t0: Schema.Number });
|
|
14
|
+
const Msg = Schema.Union(Ping, Pong);
|
|
15
|
+
const sendPing = (channel, who, timeoutMs) => Effect.gen(function* () {
|
|
16
|
+
const id = Math.random().toString(36).slice(2);
|
|
17
|
+
const wait = channel.listen
|
|
18
|
+
.pipe(Stream.flatten(), Stream.filter(Schema.is(Pong)), Stream.filter((m) => m.id === id), Stream.runHead)
|
|
19
|
+
.pipe(Effect.asVoid);
|
|
20
|
+
yield* channel.send(Ping.make({ who, id, t0: Date.now() }));
|
|
21
|
+
const res = yield* wait
|
|
22
|
+
.pipe(Effect.timeout(timeoutMs), Effect.as('ok'), Effect.catchTag('TimeoutException', () => Effect.succeed('timeout')));
|
|
23
|
+
return res;
|
|
24
|
+
});
|
|
25
|
+
Vitest.scopedLive('reload handover: leader ping should not timeout (currently fails)', (test) => Effect.gen(function* () {
|
|
26
|
+
// Timings tuned to force a single leader miss at handover
|
|
27
|
+
const RELOAD_AT_MS = 300;
|
|
28
|
+
const DROP_WINDOW_MS = 80;
|
|
29
|
+
const LEADER_TIMEOUT_MS = 50;
|
|
30
|
+
const CLIENT_TIMEOUT_MS = 400;
|
|
31
|
+
const mc = new MessageChannel();
|
|
32
|
+
const a = yield* WebChannel.messagePortChannel({ port: mc.port1, schema: Msg });
|
|
33
|
+
const b = yield* WebChannel.messagePortChannel({ port: mc.port2, schema: Msg });
|
|
34
|
+
const t0 = Date.now();
|
|
35
|
+
let dropLeaderNext = false;
|
|
36
|
+
// A: responder drop exactly one leader Pong after reload starts
|
|
37
|
+
yield* a.listen
|
|
38
|
+
.pipe(Stream.flatten(), Stream.tap((m) => Effect.gen(function* () {
|
|
39
|
+
if (Schema.is(Ping)(m)) {
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
if (m.who === 'leader' && dropLeaderNext) {
|
|
42
|
+
// Simulate handover gap: drop one leader Pong
|
|
43
|
+
// This models the observed single leader timeout after reload.
|
|
44
|
+
dropLeaderNext = false;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
yield* a.send(Pong.make({ who: m.who, id: m.id, t0: m.t0 }));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})), Stream.runDrain, Effect.forkScoped);
|
|
51
|
+
// Schedule reload marker, then leader ping (tight timeout) and client ping (looser timeout)
|
|
52
|
+
yield* Effect.sleep(RELOAD_AT_MS);
|
|
53
|
+
dropLeaderNext = true;
|
|
54
|
+
const leaderRes = yield* sendPing(b, 'leader', LEADER_TIMEOUT_MS);
|
|
55
|
+
const clientRes = yield* sendPing(b, 'clientSession', CLIENT_TIMEOUT_MS);
|
|
56
|
+
// Desired behavior: leader should not timeout across reload handover
|
|
57
|
+
// Current behavior: times out once → This assertion will FAIL, documenting the issue.
|
|
58
|
+
expect(leaderRes).toBe('ok');
|
|
59
|
+
// Client should remain healthy
|
|
60
|
+
expect(clientRes).toBe('ok');
|
|
61
|
+
}).pipe(Vitest.withTestCtx(test)));
|
|
62
|
+
//# sourceMappingURL=reload-reconnect.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reload-reconnect.test.js","sourceRoot":"","sources":["../src/reload-reconnect.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/webmesh",
|
|
3
|
-
"version": "0.4.0-dev.
|
|
3
|
+
"version": "0.4.0-dev.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
"./websocket-server": "./dist/websocket-server.js"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@livestore/utils": "0.4.0-dev.
|
|
11
|
+
"@livestore/utils": "0.4.0-dev.14"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"vitest": "3.2.4",
|
|
15
|
-
"@livestore/utils-dev": "0.4.0-dev.
|
|
15
|
+
"@livestore/utils-dev": "0.4.0-dev.14"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"package.json",
|