rivetkit 2.0.6 → 2.0.7
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/schemas/actor-persist/v1.ts +0 -6
- package/dist/tsup/actor-router-consts-B3Lu87yJ.d.cts +28 -0
- package/dist/tsup/actor-router-consts-B3Lu87yJ.d.ts +28 -0
- package/dist/tsup/{chunk-7OUKNSTU.js → chunk-2NL3KGJ7.js} +17 -14
- package/dist/tsup/chunk-2NL3KGJ7.js.map +1 -0
- package/dist/tsup/{chunk-6P6RA47N.cjs → chunk-3ALZ7EGX.cjs} +14 -10
- package/dist/tsup/chunk-3ALZ7EGX.cjs.map +1 -0
- package/dist/tsup/chunk-4EXJ4ITR.cjs +102 -0
- package/dist/tsup/chunk-4EXJ4ITR.cjs.map +1 -0
- package/dist/tsup/{chunk-ZYLTS2EM.js → chunk-54MAHBLL.js} +2 -2
- package/dist/tsup/{chunk-NTCUGYSD.cjs → chunk-7OOBMCQI.cjs} +34 -31
- package/dist/tsup/chunk-7OOBMCQI.cjs.map +1 -0
- package/dist/tsup/{chunk-VCEHU56K.js → chunk-B6N6VM37.js} +2 -2
- package/dist/tsup/{chunk-VPV4MWXR.js → chunk-DIHKN7NM.js} +3 -3
- package/dist/tsup/{chunk-MRRT2CZD.cjs → chunk-ETDWYT2P.cjs} +7 -7
- package/dist/tsup/{chunk-MRRT2CZD.cjs.map → chunk-ETDWYT2P.cjs.map} +1 -1
- package/dist/tsup/{chunk-TWGATZ3X.cjs → chunk-F7YL5G7Q.cjs} +922 -872
- package/dist/tsup/chunk-F7YL5G7Q.cjs.map +1 -0
- package/dist/tsup/{chunk-UTI5NCES.cjs → chunk-GWJTWY3G.cjs} +6 -6
- package/dist/tsup/{chunk-UTI5NCES.cjs.map → chunk-GWJTWY3G.cjs.map} +1 -1
- package/dist/tsup/{chunk-W6LN7AF5.js → chunk-KHRZPP5T.js} +866 -816
- package/dist/tsup/chunk-KHRZPP5T.js.map +1 -0
- package/dist/tsup/{chunk-5JBFVV4C.cjs → chunk-LXAVET4A.cjs} +21 -7
- package/dist/tsup/chunk-LXAVET4A.cjs.map +1 -0
- package/dist/tsup/{chunk-TCUI5JFE.cjs → chunk-NDCVQZBS.cjs} +45 -18
- package/dist/tsup/chunk-NDCVQZBS.cjs.map +1 -0
- package/dist/tsup/{chunk-4CKHQRXG.js → chunk-NII4KKHD.js} +515 -240
- package/dist/tsup/chunk-NII4KKHD.js.map +1 -0
- package/dist/tsup/{chunk-2K3JMDAN.js → chunk-NRELKXIX.js} +40 -13
- package/dist/tsup/chunk-NRELKXIX.js.map +1 -0
- package/dist/tsup/{chunk-UFWAK3X2.cjs → chunk-NUA6LOOJ.cjs} +660 -385
- package/dist/tsup/chunk-NUA6LOOJ.cjs.map +1 -0
- package/dist/tsup/{chunk-DIAYNQTE.cjs → chunk-OSK2VSJF.cjs} +12 -12
- package/dist/tsup/{chunk-DIAYNQTE.cjs.map → chunk-OSK2VSJF.cjs.map} +1 -1
- package/dist/tsup/chunk-PD6HCAJE.js +102 -0
- package/dist/tsup/chunk-PD6HCAJE.js.map +1 -0
- package/dist/tsup/{chunk-RGQR2J7S.js → chunk-RLBM6D4L.js} +20 -6
- package/dist/tsup/chunk-RLBM6D4L.js.map +1 -0
- package/dist/tsup/{chunk-KG3C7MKR.cjs → chunk-VAF63BEI.cjs} +3 -3
- package/dist/tsup/{chunk-KG3C7MKR.cjs.map → chunk-VAF63BEI.cjs.map} +1 -1
- package/dist/tsup/{chunk-G75SVQON.js → chunk-WAT5AE7S.js} +9 -5
- package/dist/tsup/chunk-WAT5AE7S.js.map +1 -0
- package/dist/tsup/{chunk-WC2PSJWN.js → chunk-YL4VZMMT.js} +2 -2
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +7 -8
- package/dist/tsup/client/mod.d.ts +7 -8
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{connection-BLemxi4f.d.ts → conn-DCSQgIlw.d.ts} +1605 -1353
- package/dist/tsup/{connection-CpDIydXf.d.cts → conn-DdzHTm2E.d.cts} +1605 -1353
- package/dist/tsup/driver-helpers/mod.cjs +31 -5
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
- package/dist/tsup/driver-helpers/mod.d.cts +7 -8
- package/dist/tsup/driver-helpers/mod.d.ts +7 -8
- package/dist/tsup/driver-helpers/mod.js +33 -7
- package/dist/tsup/driver-test-suite/mod.cjs +317 -222
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/driver-test-suite/mod.d.cts +7 -7
- package/dist/tsup/driver-test-suite/mod.d.ts +7 -7
- package/dist/tsup/driver-test-suite/mod.js +582 -487
- package/dist/tsup/driver-test-suite/mod.js.map +1 -1
- package/dist/tsup/inspector/mod.cjs +16 -6
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.d.cts +34 -7
- package/dist/tsup/inspector/mod.d.ts +34 -7
- package/dist/tsup/inspector/mod.js +17 -7
- package/dist/tsup/mod.cjs +10 -20
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +9 -7
- package/dist/tsup/mod.d.ts +9 -7
- package/dist/tsup/mod.js +9 -19
- package/dist/tsup/test/mod.cjs +11 -11
- package/dist/tsup/test/mod.d.cts +6 -7
- package/dist/tsup/test/mod.d.ts +6 -7
- package/dist/tsup/test/mod.js +10 -10
- package/dist/tsup/utils.cjs +4 -2
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +11 -1
- package/dist/tsup/utils.d.ts +11 -1
- package/dist/tsup/utils.js +3 -1
- package/package.json +8 -4
- package/src/actor/action.ts +1 -1
- package/src/actor/config.ts +1 -1
- package/src/actor/conn-drivers.ts +205 -0
- package/src/actor/conn-socket.ts +6 -0
- package/src/actor/{connection.ts → conn.ts} +78 -84
- package/src/actor/context.ts +1 -1
- package/src/actor/driver.ts +4 -43
- package/src/actor/instance.ts +162 -86
- package/src/actor/mod.ts +1 -11
- package/src/actor/persisted.ts +2 -5
- package/src/actor/protocol/old.ts +1 -1
- package/src/actor/router-endpoints.ts +142 -106
- package/src/actor/router.ts +81 -45
- package/src/actor/utils.ts +5 -1
- package/src/client/actor-conn.ts +154 -23
- package/src/client/client.ts +1 -1
- package/src/client/config.ts +7 -0
- package/src/common/actor-router-consts.ts +29 -8
- package/src/common/router.ts +2 -1
- package/src/common/versioned-data.ts +5 -5
- package/src/driver-helpers/mod.ts +14 -1
- package/src/driver-test-suite/mod.ts +11 -2
- package/src/driver-test-suite/test-inline-client-driver.ts +36 -18
- package/src/driver-test-suite/tests/actor-conn-state.ts +66 -22
- package/src/driver-test-suite/tests/actor-conn.ts +65 -126
- package/src/driver-test-suite/tests/actor-reconnect.ts +160 -0
- package/src/driver-test-suite/tests/actor-sleep.ts +0 -1
- package/src/driver-test-suite/tests/raw-websocket.ts +0 -35
- package/src/driver-test-suite/utils.ts +3 -3
- package/src/drivers/default.ts +8 -7
- package/src/drivers/engine/actor-driver.ts +53 -31
- package/src/drivers/engine/config.ts +4 -0
- package/src/drivers/file-system/actor.ts +0 -6
- package/src/drivers/file-system/global-state.ts +3 -14
- package/src/drivers/file-system/manager.ts +12 -8
- package/src/inspector/actor.ts +4 -3
- package/src/inspector/config.ts +10 -1
- package/src/inspector/mod.ts +1 -0
- package/src/inspector/utils.ts +23 -4
- package/src/manager/driver.ts +11 -1
- package/src/manager/gateway.ts +407 -0
- package/src/manager/router.ts +269 -468
- package/src/manager-api/actors.ts +61 -0
- package/src/manager-api/common.ts +4 -0
- package/src/mod.ts +1 -1
- package/src/registry/mod.ts +119 -10
- package/src/remote-manager-driver/actor-http-client.ts +30 -19
- package/src/remote-manager-driver/actor-websocket-client.ts +43 -16
- package/src/remote-manager-driver/api-endpoints.ts +19 -21
- package/src/remote-manager-driver/api-utils.ts +10 -1
- package/src/remote-manager-driver/mod.ts +51 -48
- package/src/remote-manager-driver/ws-proxy.ts +2 -9
- package/src/test/mod.ts +6 -2
- package/src/utils.ts +21 -2
- package/dist/tsup/actor-router-consts-BK6arfy8.d.cts +0 -17
- package/dist/tsup/actor-router-consts-BK6arfy8.d.ts +0 -17
- package/dist/tsup/chunk-2K3JMDAN.js.map +0 -1
- package/dist/tsup/chunk-42I3OZ3Q.js +0 -15
- package/dist/tsup/chunk-42I3OZ3Q.js.map +0 -1
- package/dist/tsup/chunk-4CKHQRXG.js.map +0 -1
- package/dist/tsup/chunk-5JBFVV4C.cjs.map +0 -1
- package/dist/tsup/chunk-6P6RA47N.cjs.map +0 -1
- package/dist/tsup/chunk-7OUKNSTU.js.map +0 -1
- package/dist/tsup/chunk-G75SVQON.js.map +0 -1
- package/dist/tsup/chunk-KUPQZYUQ.cjs +0 -15
- package/dist/tsup/chunk-KUPQZYUQ.cjs.map +0 -1
- package/dist/tsup/chunk-NTCUGYSD.cjs.map +0 -1
- package/dist/tsup/chunk-RGQR2J7S.js.map +0 -1
- package/dist/tsup/chunk-TCUI5JFE.cjs.map +0 -1
- package/dist/tsup/chunk-TWGATZ3X.cjs.map +0 -1
- package/dist/tsup/chunk-UFWAK3X2.cjs.map +0 -1
- package/dist/tsup/chunk-W6LN7AF5.js.map +0 -1
- package/dist/tsup/common-CXCe7s6i.d.cts +0 -218
- package/dist/tsup/common-CXCe7s6i.d.ts +0 -218
- package/src/actor/generic-conn-driver.ts +0 -246
- package/src/common/fake-event-source.ts +0 -267
- package/src/manager-api/routes/actors-create.ts +0 -16
- package/src/manager-api/routes/actors-delete.ts +0 -4
- package/src/manager-api/routes/actors-get-by-id.ts +0 -7
- package/src/manager-api/routes/actors-get-or-create-by-id.ts +0 -29
- package/src/manager-api/routes/actors-get.ts +0 -7
- package/src/manager-api/routes/common.ts +0 -18
- /package/dist/tsup/{chunk-ZYLTS2EM.js.map → chunk-54MAHBLL.js.map} +0 -0
- /package/dist/tsup/{chunk-VCEHU56K.js.map → chunk-B6N6VM37.js.map} +0 -0
- /package/dist/tsup/{chunk-VPV4MWXR.js.map → chunk-DIHKN7NM.js.map} +0 -0
- /package/dist/tsup/{chunk-WC2PSJWN.js.map → chunk-YL4VZMMT.js.map} +0 -0
|
@@ -145,38 +145,79 @@ export function runActorConnStateTests(driverTestConfig: DriverTestConfig) {
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
describe("Connection Lifecycle", () => {
|
|
148
|
-
test(
|
|
148
|
+
test.skipIf(
|
|
149
|
+
driverTestConfig.transport === "sse" &&
|
|
150
|
+
driverTestConfig.clientType === "inline",
|
|
151
|
+
)("should track connection and disconnection events", async (c) => {
|
|
149
152
|
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
150
153
|
|
|
154
|
+
const debugHandle = client.connStateActor.getOrCreate(undefined, {
|
|
155
|
+
params: { noCount: true },
|
|
156
|
+
});
|
|
157
|
+
|
|
151
158
|
// Create a connection
|
|
152
|
-
const
|
|
153
|
-
const conn = handle.connect();
|
|
159
|
+
const conn = client.connStateActor.getOrCreate().connect();
|
|
154
160
|
|
|
155
161
|
// Get the connection state
|
|
156
162
|
const connState = await conn.getConnectionState();
|
|
157
163
|
|
|
158
164
|
// Verify the connection is tracked
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
await vi.waitFor(async () => {
|
|
166
|
+
const connectionIds = await debugHandle.getConnectionIds();
|
|
167
|
+
expect(connectionIds).toContain(connState.id);
|
|
168
|
+
});
|
|
161
169
|
|
|
162
170
|
// Initial disconnection count
|
|
163
|
-
|
|
171
|
+
await vi.waitFor(async () => {
|
|
172
|
+
const disconnects = await debugHandle.getDisconnectionCount();
|
|
173
|
+
expect(disconnects).toBe(0);
|
|
174
|
+
});
|
|
164
175
|
|
|
165
176
|
// Dispose the connection
|
|
166
177
|
await conn.dispose();
|
|
167
178
|
|
|
179
|
+
// Validate conn count
|
|
180
|
+
await vi.waitFor(
|
|
181
|
+
async () => {
|
|
182
|
+
console.log("disconnects before");
|
|
183
|
+
const disconnects = await debugHandle.getDisconnectionCount();
|
|
184
|
+
console.log("disconnects", disconnects);
|
|
185
|
+
expect(disconnects).toBe(1);
|
|
186
|
+
},
|
|
187
|
+
// SSE takes a long time to disconnect on CF Workers
|
|
188
|
+
{
|
|
189
|
+
timeout: 10_000,
|
|
190
|
+
interval: 100,
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
|
|
168
194
|
// Create a new connection to check the disconnection count
|
|
169
|
-
const newConn =
|
|
195
|
+
const newConn = client.connStateActor.getOrCreate().connect();
|
|
170
196
|
|
|
171
|
-
// Verify
|
|
197
|
+
// Verify the connection is tracked
|
|
172
198
|
await vi.waitFor(async () => {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
expect(
|
|
199
|
+
const connectionIds = await debugHandle.getConnectionIds();
|
|
200
|
+
console.log("conn ids", connectionIds);
|
|
201
|
+
expect(connectionIds.length).toBe(1);
|
|
176
202
|
});
|
|
177
203
|
|
|
178
204
|
// Clean up
|
|
179
205
|
await newConn.dispose();
|
|
206
|
+
|
|
207
|
+
// Verify disconnection was tracked
|
|
208
|
+
await vi.waitFor(
|
|
209
|
+
async () => {
|
|
210
|
+
console.log("A");
|
|
211
|
+
const disconnects = await debugHandle.getDisconnectionCount();
|
|
212
|
+
console.log(`B ${disconnects}`);
|
|
213
|
+
expect(disconnects).toBe(2);
|
|
214
|
+
},
|
|
215
|
+
// SSE takes a long time to disconnect on CF Workers
|
|
216
|
+
{
|
|
217
|
+
timeout: 10_000,
|
|
218
|
+
interval: 100,
|
|
219
|
+
},
|
|
220
|
+
);
|
|
180
221
|
});
|
|
181
222
|
|
|
182
223
|
test("should update connection state", async (c) => {
|
|
@@ -228,17 +269,20 @@ export function runActorConnStateTests(driverTestConfig: DriverTestConfig) {
|
|
|
228
269
|
receivedMessages.push(data);
|
|
229
270
|
});
|
|
230
271
|
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
272
|
+
// TODO: SSE has race condition between subscrib eand publish message
|
|
273
|
+
await vi.waitFor(async () => {
|
|
274
|
+
// Send message from first connection to second
|
|
275
|
+
const success = await conn1.sendToConnection(
|
|
276
|
+
state2.id,
|
|
277
|
+
"Hello from conn1",
|
|
278
|
+
);
|
|
279
|
+
expect(success).toBe(true);
|
|
280
|
+
|
|
281
|
+
// Verify message was received
|
|
282
|
+
expect(receivedMessages.length).toBe(1);
|
|
283
|
+
expect(receivedMessages[0].from).toBe(state1.id);
|
|
284
|
+
expect(receivedMessages[0].message).toBe("Hello from conn1");
|
|
285
|
+
});
|
|
242
286
|
|
|
243
287
|
// Clean up
|
|
244
288
|
await conn1.dispose();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
1
|
+
import { describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { SSE_PING_INTERVAL } from "@/actor/router-endpoints";
|
|
2
3
|
import type { DriverTestConfig } from "../mod";
|
|
3
4
|
import { FAKE_TIME, setupDriverTest, waitFor } from "../utils";
|
|
4
5
|
|
|
@@ -84,28 +85,27 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
|
|
|
84
85
|
|
|
85
86
|
// Set up event listener
|
|
86
87
|
const receivedEvents: number[] = [];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
receivedEvents.push(count);
|
|
90
|
-
if (
|
|
91
|
-
receivedEvents.includes(1) &&
|
|
92
|
-
receivedEvents.includes(6) &&
|
|
93
|
-
receivedEvents.includes(9)
|
|
94
|
-
)
|
|
95
|
-
resolve(undefined);
|
|
96
|
-
});
|
|
88
|
+
connection.on("newCount", (count: number) => {
|
|
89
|
+
receivedEvents.push(count);
|
|
97
90
|
});
|
|
98
91
|
|
|
99
|
-
//
|
|
100
|
-
await
|
|
92
|
+
// TODO: There is a race condition with opening subscription and sending events on SSE, so we need to wait for a successful round trip on the event
|
|
93
|
+
await vi.waitFor(async () => {
|
|
94
|
+
// Send one RPC call over the connection to ensure it's open
|
|
95
|
+
await connection.setCount(1);
|
|
96
|
+
expect(receivedEvents).includes(1);
|
|
97
|
+
});
|
|
101
98
|
|
|
102
99
|
// Now use stateless RPC calls through the handle (no connection)
|
|
103
100
|
// These should still trigger events that the connection receives
|
|
104
|
-
await handle.
|
|
105
|
-
await handle.
|
|
101
|
+
await handle.setCount(2);
|
|
102
|
+
await handle.setCount(3);
|
|
106
103
|
|
|
107
104
|
// Wait for all events to be received
|
|
108
|
-
await
|
|
105
|
+
await vi.waitFor(() => {
|
|
106
|
+
expect(receivedEvents).includes(2);
|
|
107
|
+
expect(receivedEvents).includes(3);
|
|
108
|
+
});
|
|
109
109
|
|
|
110
110
|
// Clean up
|
|
111
111
|
await connection.dispose();
|
|
@@ -124,13 +124,17 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
|
|
|
124
124
|
receivedEvents.push(count);
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
//
|
|
128
|
-
await connection.increment(5);
|
|
129
|
-
await connection.increment(3);
|
|
130
|
-
|
|
127
|
+
// HACK: Race condition between subscribing & sending events in SSE
|
|
131
128
|
// Verify events were received
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
await vi.waitFor(
|
|
130
|
+
async () => {
|
|
131
|
+
await connection.setCount(5);
|
|
132
|
+
await connection.setCount(8);
|
|
133
|
+
expect(receivedEvents).toContain(5);
|
|
134
|
+
expect(receivedEvents).toContain(8);
|
|
135
|
+
},
|
|
136
|
+
{ timeout: 10_000 },
|
|
137
|
+
);
|
|
134
138
|
|
|
135
139
|
// Clean up
|
|
136
140
|
await connection.dispose();
|
|
@@ -154,8 +158,10 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
|
|
|
154
158
|
await connection.increment(3);
|
|
155
159
|
|
|
156
160
|
// Verify only the first event was received
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
await vi.waitFor(() => {
|
|
162
|
+
expect(receivedEvents).toEqual([5]);
|
|
163
|
+
expect(receivedEvents).not.toContain(8);
|
|
164
|
+
});
|
|
159
165
|
|
|
160
166
|
// Clean up
|
|
161
167
|
await connection.dispose();
|
|
@@ -174,17 +180,20 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
|
|
|
174
180
|
receivedEvents.push(count);
|
|
175
181
|
});
|
|
176
182
|
|
|
183
|
+
// TODO: SSE has race condition with subscriptions & publishing messages
|
|
177
184
|
// Trigger first event
|
|
178
|
-
await
|
|
185
|
+
await vi.waitFor(async () => {
|
|
186
|
+
await connection.setCount(5);
|
|
187
|
+
expect(receivedEvents).toEqual([5]);
|
|
188
|
+
});
|
|
179
189
|
|
|
180
190
|
// Unsubscribe
|
|
181
191
|
unsubscribe();
|
|
182
192
|
|
|
183
193
|
// Trigger second event, should not be received
|
|
184
|
-
await connection.
|
|
194
|
+
await connection.setCount(8);
|
|
185
195
|
|
|
186
196
|
// Verify only the first event was received
|
|
187
|
-
expect(receivedEvents).toEqual([5]);
|
|
188
197
|
expect(receivedEvents).not.toContain(8);
|
|
189
198
|
|
|
190
199
|
// Clean up
|
|
@@ -225,7 +234,10 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
|
|
|
225
234
|
});
|
|
226
235
|
|
|
227
236
|
describe("Lifecycle Hooks", () => {
|
|
228
|
-
test(
|
|
237
|
+
test.skipIf(
|
|
238
|
+
driverTestConfig.transport === "sse" &&
|
|
239
|
+
driverTestConfig.clientType === "inline",
|
|
240
|
+
)("should trigger lifecycle hooks", async (c) => {
|
|
229
241
|
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
230
242
|
|
|
231
243
|
// Create and connect
|
|
@@ -244,104 +256,31 @@ export function runActorConnTests(driverTestConfig: DriverTestConfig) {
|
|
|
244
256
|
// Disconnect should trigger onDisconnect
|
|
245
257
|
await connection.dispose();
|
|
246
258
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
// Create actor and connection
|
|
273
|
-
const handle = client.connLivenessActor.getOrCreate([
|
|
274
|
-
"test-liveness-status",
|
|
275
|
-
]);
|
|
276
|
-
const connA = handle.connect();
|
|
277
|
-
const connB = handle.connect();
|
|
278
|
-
|
|
279
|
-
const connAId = await connA.getConnectionId();
|
|
280
|
-
const connBId = await connB.getConnectionId();
|
|
281
|
-
|
|
282
|
-
// Verify connection works initially
|
|
283
|
-
await connA.increment(5);
|
|
284
|
-
await connB.increment(5);
|
|
285
|
-
|
|
286
|
-
const counter = await handle.getCounter();
|
|
287
|
-
expect(counter).toBe(10);
|
|
288
|
-
|
|
289
|
-
const connectionsStatusBeforeKill =
|
|
290
|
-
await handle.getWsConnectionsLiveness();
|
|
291
|
-
expect(connectionsStatusBeforeKill).toHaveLength(2);
|
|
292
|
-
expect(connectionsStatusBeforeKill).toContainEqual(
|
|
293
|
-
expect.objectContaining({
|
|
294
|
-
id: connAId,
|
|
295
|
-
status: "connected",
|
|
296
|
-
lastSeen: FAKE_TIME.getTime(),
|
|
297
|
-
}),
|
|
298
|
-
);
|
|
299
|
-
expect(connectionsStatusBeforeKill).toContainEqual(
|
|
300
|
-
expect.objectContaining({
|
|
301
|
-
id: connBId,
|
|
302
|
-
status: "connected",
|
|
303
|
-
lastSeen: FAKE_TIME.getTime(),
|
|
304
|
-
}),
|
|
305
|
-
);
|
|
306
|
-
|
|
307
|
-
// Kill one connection
|
|
308
|
-
await handle.kill(connAId); // instead of dispose, we use kill to simulate a disconnection (e.g. network failure)
|
|
309
|
-
// connA.dispose();
|
|
310
|
-
// we killed the connection, but the actor instance does not know about it yet
|
|
311
|
-
// it should still be in the list of connections, but with a status of "reconnecting"
|
|
312
|
-
const connectionsStatusAfterKill =
|
|
313
|
-
await handle.getWsConnectionsLiveness();
|
|
314
|
-
expect(connectionsStatusAfterKill).toEqual(
|
|
315
|
-
expect.arrayContaining([
|
|
316
|
-
expect.objectContaining({
|
|
317
|
-
id: connAId,
|
|
318
|
-
status: "reconnecting",
|
|
319
|
-
lastSeen: FAKE_TIME.getTime(),
|
|
320
|
-
}),
|
|
321
|
-
expect.objectContaining({
|
|
322
|
-
id: connBId,
|
|
323
|
-
status: "connected",
|
|
324
|
-
lastSeen: FAKE_TIME.getTime(),
|
|
325
|
-
}),
|
|
326
|
-
]),
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
// default time to wait for cleanup is 5 seconds
|
|
330
|
-
// check actor options
|
|
331
|
-
await waitFor(driverTestConfig, 5_000);
|
|
332
|
-
|
|
333
|
-
// After timeout, the killed connection should be unavailable, since the manager has cleaned it up
|
|
334
|
-
const connectionsStatusAfterCleanup =
|
|
335
|
-
await handle.getWsConnectionsLiveness();
|
|
336
|
-
expect(connectionsStatusAfterCleanup).not.toContainEqual(
|
|
337
|
-
expect.objectContaining({
|
|
338
|
-
id: connAId,
|
|
339
|
-
}),
|
|
340
|
-
);
|
|
341
|
-
expect(connectionsStatusAfterCleanup).toContainEqual(
|
|
342
|
-
expect.objectContaining({
|
|
343
|
-
id: connBId,
|
|
344
|
-
}),
|
|
259
|
+
await vi.waitFor(
|
|
260
|
+
async () => {
|
|
261
|
+
// Reconnect to check if onDisconnect was called
|
|
262
|
+
const handle = client.counterWithLifecycle.getOrCreate([
|
|
263
|
+
"test-lifecycle",
|
|
264
|
+
]);
|
|
265
|
+
const finalEvents = await handle.getEvents();
|
|
266
|
+
expect(finalEvents).toBeOneOf([
|
|
267
|
+
// Still active
|
|
268
|
+
["onStart", "onBeforeConnect", "onConnect", "onDisconnect"],
|
|
269
|
+
// Went to sleep and woke back up
|
|
270
|
+
[
|
|
271
|
+
"onStart",
|
|
272
|
+
"onBeforeConnect",
|
|
273
|
+
"onConnect",
|
|
274
|
+
"onDisconnect",
|
|
275
|
+
"onStart",
|
|
276
|
+
],
|
|
277
|
+
]);
|
|
278
|
+
},
|
|
279
|
+
// NOTE: High timeout required for Cloudflare Workers
|
|
280
|
+
{
|
|
281
|
+
timeout: 10_000,
|
|
282
|
+
interval: 100,
|
|
283
|
+
},
|
|
345
284
|
);
|
|
346
285
|
});
|
|
347
286
|
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from "vitest";
|
|
2
|
+
import type { ActorConnRaw } from "@/client/actor-conn";
|
|
3
|
+
import type { DriverTestConfig } from "../mod";
|
|
4
|
+
import { setupDriverTest } from "../utils";
|
|
5
|
+
|
|
6
|
+
export function runActorReconnectTests(driverTestConfig: DriverTestConfig) {
|
|
7
|
+
describe("Actor Reconnection Tests", () => {
|
|
8
|
+
test("should reconnect and preserve connection state after non-clean disconnect", async (c) => {
|
|
9
|
+
const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
|
|
10
|
+
|
|
11
|
+
// Create actor and connect
|
|
12
|
+
const handle = client.counterConn.getOrCreate(["test-reconnect"]);
|
|
13
|
+
const connection = handle.connect();
|
|
14
|
+
|
|
15
|
+
// Set an initial count on the connection
|
|
16
|
+
await connection.increment(5);
|
|
17
|
+
|
|
18
|
+
// Verify connection count is 1
|
|
19
|
+
const connCount1 = await connection.getConnectionCount();
|
|
20
|
+
expect(connCount1).toBe(1);
|
|
21
|
+
|
|
22
|
+
// Force disconnect (non-clean) - simulates network failure
|
|
23
|
+
const connRaw = connection as unknown as ActorConnRaw;
|
|
24
|
+
await forceUncleanDisconnect(
|
|
25
|
+
endpoint,
|
|
26
|
+
connRaw.actorId!,
|
|
27
|
+
connRaw.connectionId!,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// Wait a bit for the disconnection to be processed
|
|
31
|
+
await vi.waitFor(
|
|
32
|
+
async () => {
|
|
33
|
+
const countAfterReconnect = await connection.getCount();
|
|
34
|
+
expect(countAfterReconnect).toBe(5); // Should preserve the count
|
|
35
|
+
},
|
|
36
|
+
{ timeout: 5000, interval: 100 },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Verify connection count is still 1 (same connection reconnected)
|
|
40
|
+
const connCount2 = await connection.getConnectionCount();
|
|
41
|
+
expect(connCount2).toBe(1);
|
|
42
|
+
|
|
43
|
+
// Verify we can still increment the counter
|
|
44
|
+
const newCount = await connection.getCount();
|
|
45
|
+
expect(newCount).toBe(5);
|
|
46
|
+
|
|
47
|
+
// Clean up
|
|
48
|
+
await connection.dispose();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("should not preserve connection state after clean disconnect", async (c) => {
|
|
52
|
+
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
53
|
+
|
|
54
|
+
// Create actor and connect
|
|
55
|
+
const handle = client.counterConn.getOrCreate(["test-clean-disconnect"]);
|
|
56
|
+
const connection = handle.connect();
|
|
57
|
+
|
|
58
|
+
// Set an initial count on the connection
|
|
59
|
+
await connection.increment(10);
|
|
60
|
+
|
|
61
|
+
// Verify connection count is 1
|
|
62
|
+
const connCount1 = await connection.getConnectionCount();
|
|
63
|
+
expect(connCount1).toBe(1);
|
|
64
|
+
|
|
65
|
+
// Clean disconnect
|
|
66
|
+
await connection.dispose();
|
|
67
|
+
|
|
68
|
+
// Wait a bit to ensure disconnection is processed
|
|
69
|
+
await vi.waitFor(
|
|
70
|
+
async () => {
|
|
71
|
+
// Check that connection count is now 0
|
|
72
|
+
const handle2 = client.counterConn.get(["test-clean-disconnect"]);
|
|
73
|
+
const connCount = await handle2.getConnectionCount();
|
|
74
|
+
// This counts the current action caller
|
|
75
|
+
expect(connCount).toBe(1);
|
|
76
|
+
},
|
|
77
|
+
{ timeout: 5000 },
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Create a new connection
|
|
81
|
+
const connection2 = handle.connect();
|
|
82
|
+
|
|
83
|
+
// The count should be reset since it's a new connection
|
|
84
|
+
const countNewConnection = await connection2.getCount();
|
|
85
|
+
expect(countNewConnection).toBe(0); // Should be reset
|
|
86
|
+
|
|
87
|
+
// Verify connection count is 1 again (new connection)
|
|
88
|
+
const connCount3 = await connection2.getConnectionCount();
|
|
89
|
+
expect(connCount3).toBe(1);
|
|
90
|
+
|
|
91
|
+
// Clean up
|
|
92
|
+
await connection2.dispose();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("should handle multiple non-clean disconnects and reconnects", async (c) => {
|
|
96
|
+
const { client, endpoint } = await setupDriverTest(c, driverTestConfig);
|
|
97
|
+
|
|
98
|
+
// Create actor and connect
|
|
99
|
+
const handle = client.counterConn.getOrCreate([
|
|
100
|
+
"test-multiple-reconnect",
|
|
101
|
+
]);
|
|
102
|
+
const connection = handle.connect();
|
|
103
|
+
|
|
104
|
+
// Set an initial count
|
|
105
|
+
await connection.setCount(100);
|
|
106
|
+
|
|
107
|
+
// Perform multiple disconnect-reconnect cycles
|
|
108
|
+
for (let i = 0; i < 3; i++) {
|
|
109
|
+
// Increment before disconnect
|
|
110
|
+
await connection.increment(1);
|
|
111
|
+
|
|
112
|
+
// Force disconnect
|
|
113
|
+
const connRaw = connection as unknown as ActorConnRaw;
|
|
114
|
+
await forceUncleanDisconnect(
|
|
115
|
+
endpoint,
|
|
116
|
+
connRaw.actorId!,
|
|
117
|
+
connRaw.connectionId!,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// Wait for reconnection and verify state is preserved
|
|
121
|
+
await vi.waitFor(
|
|
122
|
+
async () => {
|
|
123
|
+
const countAfter = await connection.getCount();
|
|
124
|
+
expect(countAfter).toBe(101 + i);
|
|
125
|
+
},
|
|
126
|
+
{ timeout: 5000 },
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Verify connection count remains 1
|
|
130
|
+
const connCount = await connection.getConnectionCount();
|
|
131
|
+
expect(connCount).toBe(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Final verification
|
|
135
|
+
const finalCount = await connection.getCount();
|
|
136
|
+
expect(finalCount).toBe(103);
|
|
137
|
+
|
|
138
|
+
// Clean up
|
|
139
|
+
await connection.dispose();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function forceUncleanDisconnect(
|
|
145
|
+
endpoint: string,
|
|
146
|
+
actorId: string,
|
|
147
|
+
connId: string,
|
|
148
|
+
): Promise<void> {
|
|
149
|
+
const response = await fetch(
|
|
150
|
+
`${endpoint}/.test/force-disconnect?actor=${actorId}&conn=${connId}`,
|
|
151
|
+
{
|
|
152
|
+
method: "POST",
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
const text = await response.text();
|
|
158
|
+
throw new Error(`Failed to force disconnect: ${text}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -318,7 +318,6 @@ export function runActorSleepTests(driverTestConfig: DriverTestConfig) {
|
|
|
318
318
|
|
|
319
319
|
// Close WebSocket
|
|
320
320
|
ws.close();
|
|
321
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
322
321
|
|
|
323
322
|
// Wait for sleep timeout after WebSocket closed
|
|
324
323
|
await waitFor(driverTestConfig, SLEEP_TIMEOUT + 100);
|
|
@@ -277,41 +277,6 @@ export function runRawWebSocketTests(driverTestConfig: DriverTestConfig) {
|
|
|
277
277
|
ws.close();
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
test("should pass connection parameters through subprotocols", async (c) => {
|
|
281
|
-
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
282
|
-
|
|
283
|
-
// Create actor with connection parameters
|
|
284
|
-
const testParams = { userId: "test123", role: "admin" };
|
|
285
|
-
const actor = client.rawWebSocketActor.getOrCreate(["params"], {
|
|
286
|
-
params: testParams,
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
const ws = await actor.websocket();
|
|
290
|
-
|
|
291
|
-
await new Promise<void>((resolve) => {
|
|
292
|
-
ws.addEventListener("open", () => resolve(), { once: true });
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// Send a request to echo the auth data (which should include conn params from auth)
|
|
296
|
-
ws.send(JSON.stringify({ type: "getAuthData" }));
|
|
297
|
-
|
|
298
|
-
const response = await new Promise<any>((resolve, reject) => {
|
|
299
|
-
ws.addEventListener("message", (event: any) => {
|
|
300
|
-
const data = JSON.parse(event.data as string);
|
|
301
|
-
if (data.type === "authData") {
|
|
302
|
-
resolve(data);
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
ws.addEventListener("close", reject);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
// For now, just verify we get a response
|
|
309
|
-
// The actual connection params handling needs to be implemented
|
|
310
|
-
expect(response).toBeDefined();
|
|
311
|
-
|
|
312
|
-
ws.close();
|
|
313
|
-
});
|
|
314
|
-
|
|
315
280
|
test("should handle connection close properly", async (c) => {
|
|
316
281
|
const { client } = await setupDriverTest(c, driverTestConfig);
|
|
317
282
|
const actor = client.rawWebSocketActor.getOrCreate(["close-test"]);
|
|
@@ -39,14 +39,14 @@ export async function setupDriverTest(
|
|
|
39
39
|
});
|
|
40
40
|
} else if (driverTestConfig.clientType === "inline") {
|
|
41
41
|
// Use inline client from driver
|
|
42
|
+
const transport = driverTestConfig.transport ?? "websocket";
|
|
42
43
|
const managerDriver = createTestInlineClientDriver(
|
|
43
44
|
endpoint,
|
|
44
45
|
"bare",
|
|
45
|
-
|
|
46
|
+
transport,
|
|
46
47
|
);
|
|
47
|
-
invariant(driverTestConfig.transport, "missing transport");
|
|
48
48
|
const runConfig = RunConfigSchema.parse({
|
|
49
|
-
transport:
|
|
49
|
+
transport: transport,
|
|
50
50
|
});
|
|
51
51
|
client = createClientWithDriver(managerDriver, runConfig);
|
|
52
52
|
} else {
|
package/src/drivers/default.ts
CHANGED
|
@@ -3,15 +3,12 @@ import { loggerWithoutContext } from "@/actor/log";
|
|
|
3
3
|
import { createEngineDriver } from "@/drivers/engine/mod";
|
|
4
4
|
import { createFileSystemOrMemoryDriver } from "@/drivers/file-system/mod";
|
|
5
5
|
import type { DriverConfig, RunConfig } from "@/registry/run-config";
|
|
6
|
-
import { getEnvUniversal } from "@/utils";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Chooses the appropriate driver based on the run configuration.
|
|
10
9
|
*/
|
|
11
10
|
export function chooseDefaultDriver(runConfig: RunConfig): DriverConfig {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (engineEndpoint && runConfig.driver) {
|
|
11
|
+
if (runConfig.endpoint && runConfig.driver) {
|
|
15
12
|
throw new UserError(
|
|
16
13
|
"Cannot specify both 'engine' and 'driver' in configuration",
|
|
17
14
|
);
|
|
@@ -21,12 +18,16 @@ export function chooseDefaultDriver(runConfig: RunConfig): DriverConfig {
|
|
|
21
18
|
return runConfig.driver;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
if (
|
|
21
|
+
if (runConfig.endpoint) {
|
|
25
22
|
loggerWithoutContext().debug({
|
|
26
23
|
msg: "using rivet engine driver",
|
|
27
|
-
endpoint:
|
|
24
|
+
endpoint: runConfig.endpoint,
|
|
25
|
+
});
|
|
26
|
+
// TODO: Add all properties from config
|
|
27
|
+
return createEngineDriver({
|
|
28
|
+
endpoint: runConfig.endpoint,
|
|
29
|
+
token: runConfig.token,
|
|
28
30
|
});
|
|
29
|
-
return createEngineDriver({ endpoint: engineEndpoint });
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
loggerWithoutContext().debug({ msg: "using default file system driver" });
|