@rivetkit/engine-runner 2.0.27 → 2.0.29-rc.1
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/mod.cjs +248 -143
- package/dist/mod.cjs.map +1 -1
- package/dist/mod.d.cts +9 -1
- package/dist/mod.d.ts +9 -1
- package/dist/mod.js +239 -134
- package/dist/mod.js.map +1 -1
- package/package.json +7 -2
- package/src/actor.ts +18 -4
- package/src/mod.ts +193 -105
- package/src/stringify.ts +31 -32
- package/src/tunnel.ts +4 -13
- package/src/utils.ts +16 -0
- package/.turbo/turbo-build.log +0 -22
- package/benches/actor-lifecycle.bench.ts +0 -190
- package/benches/utils.ts +0 -143
- package/tests/lifecycle.test.ts +0 -596
- package/tests/utils.test.ts +0 -194
- package/tsconfig.json +0 -11
- package/tsup.config.ts +0 -4
- package/turbo.json +0 -4
- package/vitest.config.ts +0 -16
package/dist/mod.js
CHANGED
|
@@ -83,6 +83,23 @@ function idToStr(id) {
|
|
|
83
83
|
const bytes = new Uint8Array(id);
|
|
84
84
|
return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
85
85
|
}
|
|
86
|
+
function stringifyError(error) {
|
|
87
|
+
var _a;
|
|
88
|
+
if (error instanceof Error) {
|
|
89
|
+
return `${error.name}: ${error.message}${error.stack ? `
|
|
90
|
+
${error.stack}` : ""}`;
|
|
91
|
+
} else if (typeof error === "string") {
|
|
92
|
+
return error;
|
|
93
|
+
} else if (typeof error === "object" && error !== null) {
|
|
94
|
+
try {
|
|
95
|
+
return `${JSON.stringify(error)}`;
|
|
96
|
+
} catch {
|
|
97
|
+
return `[object ${((_a = error.constructor) == null ? void 0 : _a.name) || "Object"}]`;
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
return String(error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
86
103
|
|
|
87
104
|
// src/actor.ts
|
|
88
105
|
var RunnerActor = class {
|
|
@@ -99,6 +116,9 @@ var RunnerActor = class {
|
|
|
99
116
|
pendingRequests = [];
|
|
100
117
|
webSockets = [];
|
|
101
118
|
actorStartPromise;
|
|
119
|
+
lastCommandIdx = -1n;
|
|
120
|
+
nextEventIdx = 0n;
|
|
121
|
+
eventHistory = [];
|
|
102
122
|
/**
|
|
103
123
|
* If restoreHibernatingRequests has been called. This is used to assert
|
|
104
124
|
* that the caller is implemented correctly.
|
|
@@ -215,6 +235,14 @@ var RunnerActor = class {
|
|
|
215
235
|
this.webSockets.splice(index, 1);
|
|
216
236
|
}
|
|
217
237
|
}
|
|
238
|
+
handleAckEvents(lastEventIdx) {
|
|
239
|
+
this.eventHistory = this.eventHistory.filter(
|
|
240
|
+
(event) => event.checkpoint.index > lastEventIdx
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
recordEvent(eventWrapper) {
|
|
244
|
+
this.eventHistory.push(eventWrapper);
|
|
245
|
+
}
|
|
218
246
|
};
|
|
219
247
|
|
|
220
248
|
// src/stringify.ts
|
|
@@ -233,8 +261,6 @@ function stringifyMessageId(messageId) {
|
|
|
233
261
|
}
|
|
234
262
|
function stringifyToServerTunnelMessageKind(kind) {
|
|
235
263
|
switch (kind.tag) {
|
|
236
|
-
case "DeprecatedTunnelAck":
|
|
237
|
-
return "DeprecatedTunnelAck";
|
|
238
264
|
case "ToServerResponseStart": {
|
|
239
265
|
const { status, headers, body, stream } = kind.val;
|
|
240
266
|
const bodyStr = body === null ? "null" : stringifyArrayBuffer(body);
|
|
@@ -268,8 +294,6 @@ function stringifyToServerTunnelMessageKind(kind) {
|
|
|
268
294
|
}
|
|
269
295
|
function stringifyToClientTunnelMessageKind(kind) {
|
|
270
296
|
switch (kind.tag) {
|
|
271
|
-
case "DeprecatedTunnelAck":
|
|
272
|
-
return "DeprecatedTunnelAck";
|
|
273
297
|
case "ToClientRequestStart": {
|
|
274
298
|
const { actorId, method, path, headers, body, stream } = kind.val;
|
|
275
299
|
const bodyStr = body === null ? "null" : stringifyArrayBuffer(body);
|
|
@@ -300,30 +324,29 @@ function stringifyToClientTunnelMessageKind(kind) {
|
|
|
300
324
|
function stringifyCommand(command) {
|
|
301
325
|
switch (command.tag) {
|
|
302
326
|
case "CommandStartActor": {
|
|
303
|
-
const {
|
|
327
|
+
const { config, hibernatingRequests } = command.val;
|
|
304
328
|
const keyStr = config.key === null ? "null" : `"${config.key}"`;
|
|
305
329
|
const inputStr = config.input === null ? "null" : stringifyArrayBuffer(config.input);
|
|
306
330
|
const hibernatingRequestsStr = hibernatingRequests.length > 0 ? `[${hibernatingRequests.map((hr) => `{gatewayId: ${idToStr(hr.gatewayId)}, requestId: ${idToStr(hr.requestId)}}`).join(", ")}]` : "[]";
|
|
307
|
-
return `CommandStartActor{
|
|
331
|
+
return `CommandStartActor{config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}, hibernatingRequests: ${hibernatingRequestsStr}}`;
|
|
308
332
|
}
|
|
309
333
|
case "CommandStopActor": {
|
|
310
|
-
|
|
311
|
-
return `CommandStopActor{actorId: "${actorId}", generation: ${generation}}`;
|
|
334
|
+
return `CommandStopActor`;
|
|
312
335
|
}
|
|
313
336
|
}
|
|
314
337
|
}
|
|
315
338
|
function stringifyCommandWrapper(wrapper) {
|
|
316
|
-
return `CommandWrapper{index: ${stringifyBigInt(wrapper.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
|
|
339
|
+
return `CommandWrapper{actorId: "${wrapper.checkpoint.actorId}", generation: "${wrapper.checkpoint.generation}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
|
|
317
340
|
}
|
|
318
341
|
function stringifyEvent(event) {
|
|
319
342
|
switch (event.tag) {
|
|
320
343
|
case "EventActorIntent": {
|
|
321
|
-
const {
|
|
344
|
+
const { intent } = event.val;
|
|
322
345
|
const intentStr = intent.tag === "ActorIntentSleep" ? "Sleep" : intent.tag === "ActorIntentStop" ? "Stop" : "Unknown";
|
|
323
|
-
return `EventActorIntent{
|
|
346
|
+
return `EventActorIntent{intent: ${intentStr}}`;
|
|
324
347
|
}
|
|
325
348
|
case "EventActorStateUpdate": {
|
|
326
|
-
const {
|
|
349
|
+
const { state } = event.val;
|
|
327
350
|
let stateStr;
|
|
328
351
|
if (state.tag === "ActorStateRunning") {
|
|
329
352
|
stateStr = "Running";
|
|
@@ -334,17 +357,17 @@ function stringifyEvent(event) {
|
|
|
334
357
|
} else {
|
|
335
358
|
stateStr = "Unknown";
|
|
336
359
|
}
|
|
337
|
-
return `EventActorStateUpdate{
|
|
360
|
+
return `EventActorStateUpdate{state: ${stateStr}}`;
|
|
338
361
|
}
|
|
339
362
|
case "EventActorSetAlarm": {
|
|
340
|
-
const {
|
|
363
|
+
const { alarmTs } = event.val;
|
|
341
364
|
const alarmTsStr = alarmTs === null ? "null" : stringifyBigInt(alarmTs);
|
|
342
|
-
return `EventActorSetAlarm{
|
|
365
|
+
return `EventActorSetAlarm{alarmTs: ${alarmTsStr}}`;
|
|
343
366
|
}
|
|
344
367
|
}
|
|
345
368
|
}
|
|
346
369
|
function stringifyEventWrapper(wrapper) {
|
|
347
|
-
return `EventWrapper{index: ${stringifyBigInt(wrapper.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
|
|
370
|
+
return `EventWrapper{actorId: ${wrapper.checkpoint.actorId}, generation: "${wrapper.checkpoint.generation}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
|
|
348
371
|
}
|
|
349
372
|
function stringifyToServer(message) {
|
|
350
373
|
switch (message.tag) {
|
|
@@ -353,28 +376,27 @@ function stringifyToServer(message) {
|
|
|
353
376
|
name,
|
|
354
377
|
version,
|
|
355
378
|
totalSlots,
|
|
356
|
-
lastCommandIdx,
|
|
357
379
|
prepopulateActorNames,
|
|
358
380
|
metadata
|
|
359
381
|
} = message.val;
|
|
360
|
-
const lastCommandIdxStr = lastCommandIdx === null ? "null" : stringifyBigInt(lastCommandIdx);
|
|
361
382
|
const prepopulateActorNamesStr = prepopulateActorNames === null ? "null" : `Map(${prepopulateActorNames.size})`;
|
|
362
383
|
const metadataStr = metadata === null ? "null" : `"${metadata}"`;
|
|
363
|
-
return `ToServerInit{name: "${name}", version: ${version}, totalSlots: ${totalSlots},
|
|
384
|
+
return `ToServerInit{name: "${name}", version: ${version}, totalSlots: ${totalSlots}, prepopulateActorNames: ${prepopulateActorNamesStr}, metadata: ${metadataStr}}`;
|
|
364
385
|
}
|
|
365
386
|
case "ToServerEvents": {
|
|
366
387
|
const events = message.val;
|
|
367
388
|
return `ToServerEvents{count: ${events.length}, events: [${events.map((e) => stringifyEventWrapper(e)).join(", ")}]}`;
|
|
368
389
|
}
|
|
369
390
|
case "ToServerAckCommands": {
|
|
370
|
-
const {
|
|
371
|
-
|
|
391
|
+
const { lastCommandCheckpoints } = message.val;
|
|
392
|
+
const checkpointsStr = lastCommandCheckpoints.length > 0 ? `[${lastCommandCheckpoints.map((cp) => `{actorId: "${cp.actorId}", index: ${stringifyBigInt(cp.index)}}`).join(", ")}]` : "[]";
|
|
393
|
+
return `ToServerAckCommands{lastCommandCheckpoints: ${checkpointsStr}}`;
|
|
372
394
|
}
|
|
373
395
|
case "ToServerStopping":
|
|
374
396
|
return "ToServerStopping";
|
|
375
|
-
case "
|
|
397
|
+
case "ToServerPong": {
|
|
376
398
|
const { ts } = message.val;
|
|
377
|
-
return `
|
|
399
|
+
return `ToServerPong{ts: ${stringifyBigInt(ts)}}`;
|
|
378
400
|
}
|
|
379
401
|
case "ToServerKvRequest": {
|
|
380
402
|
const { actorId, requestId, data } = message.val;
|
|
@@ -390,19 +412,21 @@ function stringifyToServer(message) {
|
|
|
390
412
|
function stringifyToClient(message) {
|
|
391
413
|
switch (message.tag) {
|
|
392
414
|
case "ToClientInit": {
|
|
393
|
-
const { runnerId,
|
|
415
|
+
const { runnerId, metadata } = message.val;
|
|
394
416
|
const metadataStr = `{runnerLostThreshold: ${stringifyBigInt(metadata.runnerLostThreshold)}}`;
|
|
395
|
-
return `ToClientInit{runnerId: "${runnerId}",
|
|
417
|
+
return `ToClientInit{runnerId: "${runnerId}", metadata: ${metadataStr}}`;
|
|
396
418
|
}
|
|
397
|
-
case "
|
|
398
|
-
|
|
419
|
+
case "ToClientPing":
|
|
420
|
+
const { ts } = message.val;
|
|
421
|
+
return `ToClientPing{ts: ${stringifyBigInt(ts)}}`;
|
|
399
422
|
case "ToClientCommands": {
|
|
400
423
|
const commands = message.val;
|
|
401
424
|
return `ToClientCommands{count: ${commands.length}, commands: [${commands.map((c) => stringifyCommandWrapper(c)).join(", ")}]}`;
|
|
402
425
|
}
|
|
403
426
|
case "ToClientAckEvents": {
|
|
404
|
-
const {
|
|
405
|
-
|
|
427
|
+
const { lastEventCheckpoints } = message.val;
|
|
428
|
+
const checkpointsStr = lastEventCheckpoints.length > 0 ? `[${lastEventCheckpoints.map((cp) => `{actorId: "${cp.actorId}", index: ${stringifyBigInt(cp.index)}}`).join(", ")}]` : "[]";
|
|
429
|
+
return `ToClientAckEvents{lastEventCheckpoints: ${checkpointsStr}}`;
|
|
406
430
|
}
|
|
407
431
|
case "ToClientKvResponse": {
|
|
408
432
|
const { requestId, data } = message.val;
|
|
@@ -893,11 +917,6 @@ var WebSocketTunnelAdapter = class {
|
|
|
893
917
|
};
|
|
894
918
|
|
|
895
919
|
// src/tunnel.ts
|
|
896
|
-
var RunnerShutdownError = class extends Error {
|
|
897
|
-
constructor() {
|
|
898
|
-
super("Runner shut down");
|
|
899
|
-
}
|
|
900
|
-
};
|
|
901
920
|
var Tunnel = class {
|
|
902
921
|
#runner;
|
|
903
922
|
/** Maps request IDs to actor IDs for lookup */
|
|
@@ -1019,7 +1038,7 @@ var Tunnel = class {
|
|
|
1019
1038
|
(_a2 = this.log) == null ? void 0 : _a2.error({
|
|
1020
1039
|
msg: "error creating websocket during restore",
|
|
1021
1040
|
requestId: requestIdStr,
|
|
1022
|
-
err
|
|
1041
|
+
error: stringifyError(err)
|
|
1023
1042
|
});
|
|
1024
1043
|
this.#sendMessage(gatewayId, requestId, {
|
|
1025
1044
|
tag: "ToServerWebSocketClose",
|
|
@@ -1068,7 +1087,7 @@ var Tunnel = class {
|
|
|
1068
1087
|
(_a2 = this.log) == null ? void 0 : _a2.error({
|
|
1069
1088
|
msg: "error creating stale websocket during restore",
|
|
1070
1089
|
requestId: requestIdStr,
|
|
1071
|
-
err
|
|
1090
|
+
error: stringifyError(err)
|
|
1072
1091
|
});
|
|
1073
1092
|
});
|
|
1074
1093
|
backgroundOperations.push(cleanupOperation);
|
|
@@ -1348,8 +1367,6 @@ var Tunnel = class {
|
|
|
1348
1367
|
message.messageKind.val
|
|
1349
1368
|
);
|
|
1350
1369
|
break;
|
|
1351
|
-
case "DeprecatedTunnelAck":
|
|
1352
|
-
break;
|
|
1353
1370
|
default:
|
|
1354
1371
|
unreachable(message.messageKind);
|
|
1355
1372
|
}
|
|
@@ -1738,10 +1755,14 @@ async function importWebSocket() {
|
|
|
1738
1755
|
|
|
1739
1756
|
// src/mod.ts
|
|
1740
1757
|
var KV_EXPIRE = 3e4;
|
|
1741
|
-
var PROTOCOL_VERSION =
|
|
1742
|
-
var RUNNER_PING_INTERVAL = 3e3;
|
|
1758
|
+
var PROTOCOL_VERSION = 5;
|
|
1743
1759
|
var EVENT_BACKLOG_WARN_THRESHOLD = 1e4;
|
|
1744
1760
|
var SIGNAL_HANDLERS = [];
|
|
1761
|
+
var RunnerShutdownError = class extends Error {
|
|
1762
|
+
constructor() {
|
|
1763
|
+
super("Runner shut down");
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1745
1766
|
var Runner = class {
|
|
1746
1767
|
#config;
|
|
1747
1768
|
get config() {
|
|
@@ -1751,9 +1772,6 @@ var Runner = class {
|
|
|
1751
1772
|
// WebSocket
|
|
1752
1773
|
__pegboardWebSocket;
|
|
1753
1774
|
runnerId;
|
|
1754
|
-
#lastCommandIdx = -1;
|
|
1755
|
-
#pingLoop;
|
|
1756
|
-
#nextEventIdx = 0n;
|
|
1757
1775
|
#started = false;
|
|
1758
1776
|
#shutdown = false;
|
|
1759
1777
|
#shuttingDown = false;
|
|
@@ -1763,7 +1781,6 @@ var Runner = class {
|
|
|
1763
1781
|
#runnerLostThreshold;
|
|
1764
1782
|
#runnerLostTimeout;
|
|
1765
1783
|
// Event storage for resending
|
|
1766
|
-
#eventHistory = [];
|
|
1767
1784
|
#eventBacklogWarned = false;
|
|
1768
1785
|
// Command acknowledgment
|
|
1769
1786
|
#ackInterval;
|
|
@@ -1794,7 +1811,15 @@ var Runner = class {
|
|
|
1794
1811
|
this.#config = config;
|
|
1795
1812
|
if (this.#config.logger) setLogger(this.#config.logger);
|
|
1796
1813
|
this.#kvCleanupInterval = setInterval(() => {
|
|
1797
|
-
|
|
1814
|
+
var _a;
|
|
1815
|
+
try {
|
|
1816
|
+
this.#cleanupOldKvRequests();
|
|
1817
|
+
} catch (err) {
|
|
1818
|
+
(_a = this.log) == null ? void 0 : _a.error({
|
|
1819
|
+
msg: "error cleaning up kv requests",
|
|
1820
|
+
error: stringifyError(err)
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1798
1823
|
}, 15e3);
|
|
1799
1824
|
}
|
|
1800
1825
|
// MARK: Manage actors
|
|
@@ -1809,7 +1834,11 @@ var Runner = class {
|
|
|
1809
1834
|
this.#sendActorIntent(actorId, actor.generation, "stop");
|
|
1810
1835
|
}
|
|
1811
1836
|
async forceStopActor(actorId, generation) {
|
|
1812
|
-
var _a;
|
|
1837
|
+
var _a, _b;
|
|
1838
|
+
(_a = this.log) == null ? void 0 : _a.debug({
|
|
1839
|
+
msg: "force stopping actor",
|
|
1840
|
+
actorId
|
|
1841
|
+
});
|
|
1813
1842
|
const actor = this.getActor(actorId, generation);
|
|
1814
1843
|
if (!actor) return;
|
|
1815
1844
|
try {
|
|
@@ -1817,18 +1846,32 @@ var Runner = class {
|
|
|
1817
1846
|
} catch (err) {
|
|
1818
1847
|
console.error(`Error in onActorStop for actor ${actorId}:`, err);
|
|
1819
1848
|
}
|
|
1820
|
-
(
|
|
1821
|
-
this.#removeActor(actorId, generation);
|
|
1849
|
+
(_b = this.#tunnel) == null ? void 0 : _b.closeActiveRequests(actor);
|
|
1822
1850
|
this.#sendActorStateUpdate(actorId, actor.generation, "stopped");
|
|
1851
|
+
this.#removeActor(actorId, generation);
|
|
1823
1852
|
}
|
|
1824
|
-
#
|
|
1853
|
+
#handleLost() {
|
|
1825
1854
|
var _a;
|
|
1826
1855
|
(_a = this.log) == null ? void 0 : _a.info({
|
|
1827
|
-
msg: "stopping all actors due to runner lost threshold
|
|
1856
|
+
msg: "stopping all actors due to runner lost threshold"
|
|
1828
1857
|
});
|
|
1858
|
+
for (const [_, request] of this.#kvRequests.entries()) {
|
|
1859
|
+
request.reject(new RunnerShutdownError());
|
|
1860
|
+
}
|
|
1861
|
+
this.#kvRequests.clear();
|
|
1862
|
+
this.#stopAllActors();
|
|
1863
|
+
}
|
|
1864
|
+
#stopAllActors() {
|
|
1829
1865
|
const actorIds = Array.from(this.#actors.keys());
|
|
1830
1866
|
for (const actorId of actorIds) {
|
|
1831
|
-
this.forceStopActor(actorId)
|
|
1867
|
+
this.forceStopActor(actorId).catch((err) => {
|
|
1868
|
+
var _a;
|
|
1869
|
+
(_a = this.log) == null ? void 0 : _a.error({
|
|
1870
|
+
msg: "error stopping actor",
|
|
1871
|
+
actorId,
|
|
1872
|
+
error: stringifyError(err)
|
|
1873
|
+
});
|
|
1874
|
+
});
|
|
1832
1875
|
}
|
|
1833
1876
|
}
|
|
1834
1877
|
getActor(actorId, generation) {
|
|
@@ -1956,10 +1999,6 @@ var Runner = class {
|
|
|
1956
1999
|
clearTimeout(this.#runnerLostTimeout);
|
|
1957
2000
|
this.#runnerLostTimeout = void 0;
|
|
1958
2001
|
}
|
|
1959
|
-
if (this.#pingLoop) {
|
|
1960
|
-
clearInterval(this.#pingLoop);
|
|
1961
|
-
this.#pingLoop = void 0;
|
|
1962
|
-
}
|
|
1963
2002
|
if (this.#ackInterval) {
|
|
1964
2003
|
clearInterval(this.#ackInterval);
|
|
1965
2004
|
this.#ackInterval = void 0;
|
|
@@ -2167,7 +2206,6 @@ var Runner = class {
|
|
|
2167
2206
|
name: this.#config.runnerName,
|
|
2168
2207
|
version: this.#config.version,
|
|
2169
2208
|
totalSlots: this.#config.totalSlots,
|
|
2170
|
-
lastCommandIdx: this.#lastCommandIdx >= 0 ? BigInt(this.#lastCommandIdx) : null,
|
|
2171
2209
|
prepopulateActorNames: new Map(
|
|
2172
2210
|
Object.entries(this.#config.prepopulateActorNames).map(
|
|
2173
2211
|
([name, data]) => [
|
|
@@ -2182,39 +2220,29 @@ var Runner = class {
|
|
|
2182
2220
|
tag: "ToServerInit",
|
|
2183
2221
|
val: init
|
|
2184
2222
|
});
|
|
2185
|
-
const pingLoop = setInterval(() => {
|
|
2186
|
-
var _a3;
|
|
2187
|
-
if (ws.readyState === 1) {
|
|
2188
|
-
this.__sendToServer({
|
|
2189
|
-
tag: "ToServerPing",
|
|
2190
|
-
val: {
|
|
2191
|
-
ts: BigInt(Date.now())
|
|
2192
|
-
}
|
|
2193
|
-
});
|
|
2194
|
-
} else {
|
|
2195
|
-
clearInterval(pingLoop);
|
|
2196
|
-
(_a3 = this.log) == null ? void 0 : _a3.info({
|
|
2197
|
-
msg: "WebSocket not open, stopping ping loop"
|
|
2198
|
-
});
|
|
2199
|
-
}
|
|
2200
|
-
}, RUNNER_PING_INTERVAL);
|
|
2201
|
-
this.#pingLoop = pingLoop;
|
|
2202
2223
|
const ackInterval = 5 * 60 * 1e3;
|
|
2203
2224
|
const ackLoop = setInterval(() => {
|
|
2204
|
-
var _a3;
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2225
|
+
var _a3, _b2;
|
|
2226
|
+
try {
|
|
2227
|
+
if (ws.readyState === 1) {
|
|
2228
|
+
this.#sendCommandAcknowledgment();
|
|
2229
|
+
} else {
|
|
2230
|
+
clearInterval(ackLoop);
|
|
2231
|
+
(_a3 = this.log) == null ? void 0 : _a3.info({
|
|
2232
|
+
msg: "WebSocket not open, stopping ack loop"
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
} catch (err) {
|
|
2236
|
+
(_b2 = this.log) == null ? void 0 : _b2.error({
|
|
2237
|
+
msg: "error in command acknowledgment loop",
|
|
2238
|
+
error: stringifyError(err)
|
|
2211
2239
|
});
|
|
2212
2240
|
}
|
|
2213
2241
|
}, ackInterval);
|
|
2214
2242
|
this.#ackInterval = ackLoop;
|
|
2215
2243
|
});
|
|
2216
2244
|
ws.addEventListener("message", async (ev) => {
|
|
2217
|
-
var _a2, _b, _c, _d, _e
|
|
2245
|
+
var _a2, _b, _c, _d, _e;
|
|
2218
2246
|
let buf;
|
|
2219
2247
|
if (ev.data instanceof Blob) {
|
|
2220
2248
|
buf = new Uint8Array(await ev.data.arrayBuffer());
|
|
@@ -2232,16 +2260,15 @@ var Runner = class {
|
|
|
2232
2260
|
const init = message.val;
|
|
2233
2261
|
if (this.runnerId !== init.runnerId) {
|
|
2234
2262
|
this.runnerId = init.runnerId;
|
|
2235
|
-
this.#
|
|
2263
|
+
this.#stopAllActors();
|
|
2236
2264
|
}
|
|
2237
2265
|
this.#runnerLostThreshold = ((_b = init.metadata) == null ? void 0 : _b.runnerLostThreshold) ? Number(init.metadata.runnerLostThreshold) : void 0;
|
|
2238
2266
|
(_c = this.log) == null ? void 0 : _c.info({
|
|
2239
2267
|
msg: "received init",
|
|
2240
|
-
lastEventIdx: init.lastEventIdx,
|
|
2241
2268
|
runnerLostThreshold: this.#runnerLostThreshold
|
|
2242
2269
|
});
|
|
2243
2270
|
this.#processUnsentKvRequests();
|
|
2244
|
-
this.#resendUnacknowledgedEvents(
|
|
2271
|
+
this.#resendUnacknowledgedEvents();
|
|
2245
2272
|
(_d = this.#tunnel) == null ? void 0 : _d.resendBufferedEvents();
|
|
2246
2273
|
this.#config.onConnected();
|
|
2247
2274
|
} else if (message.tag === "ToClientCommands") {
|
|
@@ -2253,10 +2280,20 @@ var Runner = class {
|
|
|
2253
2280
|
const kvResponse = message.val;
|
|
2254
2281
|
this.#handleKvResponse(kvResponse);
|
|
2255
2282
|
} else if (message.tag === "ToClientTunnelMessage") {
|
|
2256
|
-
(_e = this.#tunnel) == null ? void 0 : _e.handleTunnelMessage(message.val)
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2283
|
+
(_e = this.#tunnel) == null ? void 0 : _e.handleTunnelMessage(message.val).catch((err) => {
|
|
2284
|
+
var _a3;
|
|
2285
|
+
(_a3 = this.log) == null ? void 0 : _a3.error({
|
|
2286
|
+
msg: "error handling tunnel message",
|
|
2287
|
+
error: stringifyError(err)
|
|
2288
|
+
});
|
|
2289
|
+
});
|
|
2290
|
+
} else if (message.tag === "ToClientPing") {
|
|
2291
|
+
this.__sendToServer({
|
|
2292
|
+
tag: "ToServerPong",
|
|
2293
|
+
val: {
|
|
2294
|
+
ts: message.val.ts
|
|
2295
|
+
}
|
|
2296
|
+
});
|
|
2260
2297
|
} else {
|
|
2261
2298
|
unreachable(message);
|
|
2262
2299
|
}
|
|
@@ -2273,7 +2310,15 @@ var Runner = class {
|
|
|
2273
2310
|
seconds: this.#runnerLostThreshold / 1e3
|
|
2274
2311
|
});
|
|
2275
2312
|
this.#runnerLostTimeout = setTimeout(() => {
|
|
2276
|
-
|
|
2313
|
+
var _a3;
|
|
2314
|
+
try {
|
|
2315
|
+
this.#handleLost();
|
|
2316
|
+
} catch (err) {
|
|
2317
|
+
(_a3 = this.log) == null ? void 0 : _a3.error({
|
|
2318
|
+
msg: "error handling runner lost",
|
|
2319
|
+
error: stringifyError(err)
|
|
2320
|
+
});
|
|
2321
|
+
}
|
|
2277
2322
|
}, this.#runnerLostThreshold);
|
|
2278
2323
|
}
|
|
2279
2324
|
this.#scheduleReconnect();
|
|
@@ -2299,10 +2344,6 @@ var Runner = class {
|
|
|
2299
2344
|
}
|
|
2300
2345
|
this.#config.onDisconnected(ev.code, ev.reason);
|
|
2301
2346
|
}
|
|
2302
|
-
if (this.#pingLoop) {
|
|
2303
|
-
clearInterval(this.#pingLoop);
|
|
2304
|
-
this.#pingLoop = void 0;
|
|
2305
|
-
}
|
|
2306
2347
|
if (this.#ackInterval) {
|
|
2307
2348
|
clearInterval(this.#ackInterval);
|
|
2308
2349
|
this.#ackInterval = void 0;
|
|
@@ -2314,7 +2355,15 @@ var Runner = class {
|
|
|
2314
2355
|
seconds: this.#runnerLostThreshold / 1e3
|
|
2315
2356
|
});
|
|
2316
2357
|
this.#runnerLostTimeout = setTimeout(() => {
|
|
2317
|
-
|
|
2358
|
+
var _a3;
|
|
2359
|
+
try {
|
|
2360
|
+
this.#handleLost();
|
|
2361
|
+
} catch (err) {
|
|
2362
|
+
(_a3 = this.log) == null ? void 0 : _a3.error({
|
|
2363
|
+
msg: "error handling runner lost",
|
|
2364
|
+
error: stringifyError(err)
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2318
2367
|
}, this.#runnerLostThreshold);
|
|
2319
2368
|
}
|
|
2320
2369
|
this.#scheduleReconnect();
|
|
@@ -2329,43 +2378,75 @@ var Runner = class {
|
|
|
2329
2378
|
});
|
|
2330
2379
|
for (const commandWrapper of commands) {
|
|
2331
2380
|
if (commandWrapper.inner.tag === "CommandStartActor") {
|
|
2332
|
-
this.#handleCommandStartActor(commandWrapper)
|
|
2381
|
+
this.#handleCommandStartActor(commandWrapper).catch((err) => {
|
|
2382
|
+
var _a2;
|
|
2383
|
+
(_a2 = this.log) == null ? void 0 : _a2.error({
|
|
2384
|
+
msg: "error handling start actor command",
|
|
2385
|
+
actorId: commandWrapper.checkpoint.actorId,
|
|
2386
|
+
error: stringifyError(err)
|
|
2387
|
+
});
|
|
2388
|
+
});
|
|
2389
|
+
const actor = this.getActor(
|
|
2390
|
+
commandWrapper.checkpoint.actorId,
|
|
2391
|
+
commandWrapper.checkpoint.generation
|
|
2392
|
+
);
|
|
2393
|
+
if (actor) actor.lastCommandIdx = commandWrapper.checkpoint.index;
|
|
2333
2394
|
} else if (commandWrapper.inner.tag === "CommandStopActor") {
|
|
2334
|
-
this.#handleCommandStopActor(commandWrapper)
|
|
2395
|
+
this.#handleCommandStopActor(commandWrapper).catch((err) => {
|
|
2396
|
+
var _a2;
|
|
2397
|
+
(_a2 = this.log) == null ? void 0 : _a2.error({
|
|
2398
|
+
msg: "error handling stop actor command",
|
|
2399
|
+
actorId: commandWrapper.checkpoint.actorId,
|
|
2400
|
+
error: stringifyError(err)
|
|
2401
|
+
});
|
|
2402
|
+
});
|
|
2335
2403
|
} else {
|
|
2336
2404
|
unreachable(commandWrapper.inner);
|
|
2337
2405
|
}
|
|
2338
|
-
this.#lastCommandIdx = Number(commandWrapper.index);
|
|
2339
2406
|
}
|
|
2340
2407
|
}
|
|
2341
2408
|
#handleAckEvents(ack) {
|
|
2342
2409
|
var _a;
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2410
|
+
let originalTotalEvents = Array.from(this.#actors).reduce(
|
|
2411
|
+
(s, [_, actor]) => s + actor.eventHistory.length,
|
|
2412
|
+
0
|
|
2413
|
+
);
|
|
2414
|
+
for (const [_, actor] of this.#actors) {
|
|
2415
|
+
let checkpoint = ack.lastEventCheckpoints.find(
|
|
2416
|
+
(x) => x.actorId == actor.actorId
|
|
2417
|
+
);
|
|
2418
|
+
if (checkpoint) actor.handleAckEvents(checkpoint.index);
|
|
2419
|
+
}
|
|
2420
|
+
const totalEvents = Array.from(this.#actors).reduce(
|
|
2421
|
+
(s, [_, actor]) => s + actor.eventHistory.length,
|
|
2422
|
+
0
|
|
2347
2423
|
);
|
|
2348
|
-
const prunedCount =
|
|
2424
|
+
const prunedCount = originalTotalEvents - totalEvents;
|
|
2349
2425
|
if (prunedCount > 0) {
|
|
2350
2426
|
(_a = this.log) == null ? void 0 : _a.info({
|
|
2351
2427
|
msg: "pruned acknowledged events",
|
|
2352
|
-
lastAckedIdx: lastAckedIdx.toString(),
|
|
2353
2428
|
prunedCount
|
|
2354
2429
|
});
|
|
2355
2430
|
}
|
|
2356
|
-
if (
|
|
2431
|
+
if (totalEvents <= EVENT_BACKLOG_WARN_THRESHOLD) {
|
|
2357
2432
|
this.#eventBacklogWarned = false;
|
|
2358
2433
|
}
|
|
2359
2434
|
}
|
|
2360
2435
|
/** Track events to send to the server in case we need to resend it on disconnect. */
|
|
2361
2436
|
#recordEvent(eventWrapper) {
|
|
2362
2437
|
var _a;
|
|
2363
|
-
this
|
|
2364
|
-
if (
|
|
2438
|
+
const actor = this.getActor(eventWrapper.checkpoint.actorId);
|
|
2439
|
+
if (!actor) return;
|
|
2440
|
+
actor.recordEvent(eventWrapper);
|
|
2441
|
+
let totalEvents = Array.from(this.#actors).reduce(
|
|
2442
|
+
(s, [_, actor2]) => s + actor2.eventHistory.length,
|
|
2443
|
+
0
|
|
2444
|
+
);
|
|
2445
|
+
if (totalEvents > EVENT_BACKLOG_WARN_THRESHOLD && !this.#eventBacklogWarned) {
|
|
2365
2446
|
this.#eventBacklogWarned = true;
|
|
2366
2447
|
(_a = this.log) == null ? void 0 : _a.warn({
|
|
2367
2448
|
msg: "unacknowledged event backlog exceeds threshold",
|
|
2368
|
-
backlogSize:
|
|
2449
|
+
backlogSize: totalEvents,
|
|
2369
2450
|
threshold: EVENT_BACKLOG_WARN_THRESHOLD
|
|
2370
2451
|
});
|
|
2371
2452
|
}
|
|
@@ -2374,8 +2455,8 @@ var Runner = class {
|
|
|
2374
2455
|
var _a, _b, _c, _d;
|
|
2375
2456
|
if (!this.#tunnel) throw new Error("missing tunnel on actor start");
|
|
2376
2457
|
const startCommand = commandWrapper.inner.val;
|
|
2377
|
-
const actorId =
|
|
2378
|
-
const generation =
|
|
2458
|
+
const actorId = commandWrapper.checkpoint.actorId;
|
|
2459
|
+
const generation = commandWrapper.checkpoint.generation;
|
|
2379
2460
|
const config = startCommand.config;
|
|
2380
2461
|
const actorConfig = {
|
|
2381
2462
|
name: config.name,
|
|
@@ -2433,11 +2514,13 @@ var Runner = class {
|
|
|
2433
2514
|
}
|
|
2434
2515
|
async #handleCommandStopActor(commandWrapper) {
|
|
2435
2516
|
const stopCommand = commandWrapper.inner.val;
|
|
2436
|
-
const actorId =
|
|
2437
|
-
const generation =
|
|
2517
|
+
const actorId = commandWrapper.checkpoint.actorId;
|
|
2518
|
+
const generation = commandWrapper.checkpoint.generation;
|
|
2438
2519
|
await this.forceStopActor(actorId, generation);
|
|
2439
2520
|
}
|
|
2440
2521
|
#sendActorIntent(actorId, generation, intentType) {
|
|
2522
|
+
const actor = this.getActor(actorId, generation);
|
|
2523
|
+
if (!actor) return;
|
|
2441
2524
|
let actorIntent;
|
|
2442
2525
|
if (intentType === "sleep") {
|
|
2443
2526
|
actorIntent = { tag: "ActorIntentSleep", val: null };
|
|
@@ -2450,13 +2533,14 @@ var Runner = class {
|
|
|
2450
2533
|
unreachable(intentType);
|
|
2451
2534
|
}
|
|
2452
2535
|
const intentEvent = {
|
|
2453
|
-
actorId,
|
|
2454
|
-
generation,
|
|
2455
2536
|
intent: actorIntent
|
|
2456
2537
|
};
|
|
2457
|
-
const eventIndex = this.#nextEventIdx++;
|
|
2458
2538
|
const eventWrapper = {
|
|
2459
|
-
|
|
2539
|
+
checkpoint: {
|
|
2540
|
+
actorId,
|
|
2541
|
+
generation,
|
|
2542
|
+
index: actor.nextEventIdx++
|
|
2543
|
+
},
|
|
2460
2544
|
inner: {
|
|
2461
2545
|
tag: "EventActorIntent",
|
|
2462
2546
|
val: intentEvent
|
|
@@ -2469,6 +2553,8 @@ var Runner = class {
|
|
|
2469
2553
|
});
|
|
2470
2554
|
}
|
|
2471
2555
|
#sendActorStateUpdate(actorId, generation, stateType) {
|
|
2556
|
+
const actor = this.getActor(actorId, generation);
|
|
2557
|
+
if (!actor) return;
|
|
2472
2558
|
let actorState;
|
|
2473
2559
|
if (stateType === "running") {
|
|
2474
2560
|
actorState = { tag: "ActorStateRunning", val: null };
|
|
@@ -2484,13 +2570,14 @@ var Runner = class {
|
|
|
2484
2570
|
unreachable(stateType);
|
|
2485
2571
|
}
|
|
2486
2572
|
const stateUpdateEvent = {
|
|
2487
|
-
actorId,
|
|
2488
|
-
generation,
|
|
2489
2573
|
state: actorState
|
|
2490
2574
|
};
|
|
2491
|
-
const eventIndex = this.#nextEventIdx++;
|
|
2492
2575
|
const eventWrapper = {
|
|
2493
|
-
|
|
2576
|
+
checkpoint: {
|
|
2577
|
+
actorId,
|
|
2578
|
+
generation,
|
|
2579
|
+
index: actor.nextEventIdx++
|
|
2580
|
+
},
|
|
2494
2581
|
inner: {
|
|
2495
2582
|
tag: "EventActorStateUpdate",
|
|
2496
2583
|
val: stateUpdateEvent
|
|
@@ -2503,13 +2590,21 @@ var Runner = class {
|
|
|
2503
2590
|
});
|
|
2504
2591
|
}
|
|
2505
2592
|
#sendCommandAcknowledgment() {
|
|
2506
|
-
|
|
2507
|
-
|
|
2593
|
+
const lastCommandCheckpoints = [];
|
|
2594
|
+
for (const [_, actor] of this.#actors) {
|
|
2595
|
+
if (actor.lastCommandIdx < 0) {
|
|
2596
|
+
continue;
|
|
2597
|
+
}
|
|
2598
|
+
lastCommandCheckpoints.push({
|
|
2599
|
+
actorId: actor.actorId,
|
|
2600
|
+
generation: actor.generation,
|
|
2601
|
+
index: actor.lastCommandIdx
|
|
2602
|
+
});
|
|
2508
2603
|
}
|
|
2509
2604
|
this.__sendToServer({
|
|
2510
2605
|
tag: "ToServerAckCommands",
|
|
2511
2606
|
val: {
|
|
2512
|
-
|
|
2607
|
+
lastCommandCheckpoints
|
|
2513
2608
|
}
|
|
2514
2609
|
});
|
|
2515
2610
|
}
|
|
@@ -2739,13 +2834,14 @@ var Runner = class {
|
|
|
2739
2834
|
const actor = this.getActor(actorId, generation);
|
|
2740
2835
|
if (!actor) return;
|
|
2741
2836
|
const alarmEvent = {
|
|
2742
|
-
actorId,
|
|
2743
|
-
generation: actor.generation,
|
|
2744
2837
|
alarmTs: alarmTs !== null ? BigInt(alarmTs) : null
|
|
2745
2838
|
};
|
|
2746
|
-
const eventIndex = this.#nextEventIdx++;
|
|
2747
2839
|
const eventWrapper = {
|
|
2748
|
-
|
|
2840
|
+
checkpoint: {
|
|
2841
|
+
actorId,
|
|
2842
|
+
generation: actor.generation,
|
|
2843
|
+
index: actor.nextEventIdx++
|
|
2844
|
+
},
|
|
2749
2845
|
inner: {
|
|
2750
2846
|
tag: "EventActorSetAlarm",
|
|
2751
2847
|
val: alarmEvent
|
|
@@ -2872,7 +2968,8 @@ var Runner = class {
|
|
|
2872
2968
|
const data = protocol.encodeToServerlessServer({
|
|
2873
2969
|
tag: "ToServerlessServerInit",
|
|
2874
2970
|
val: {
|
|
2875
|
-
runnerId: this.runnerId
|
|
2971
|
+
runnerId: this.runnerId,
|
|
2972
|
+
runnerProtocolVersion: PROTOCOL_VERSION
|
|
2876
2973
|
}
|
|
2877
2974
|
});
|
|
2878
2975
|
const buffer = Buffer.alloc(data.length + 2);
|
|
@@ -2897,26 +2994,33 @@ var Runner = class {
|
|
|
2897
2994
|
(_b = this.log) == null ? void 0 : _b.debug({
|
|
2898
2995
|
msg: `Scheduling reconnect attempt ${this.#reconnectAttempt + 1} in ${delay}ms`
|
|
2899
2996
|
});
|
|
2900
|
-
this.#reconnectTimeout = setTimeout(
|
|
2997
|
+
this.#reconnectTimeout = setTimeout(() => {
|
|
2901
2998
|
var _a2;
|
|
2902
2999
|
if (!this.#shutdown) {
|
|
2903
3000
|
this.#reconnectAttempt++;
|
|
2904
3001
|
(_a2 = this.log) == null ? void 0 : _a2.debug({
|
|
2905
3002
|
msg: `Attempting to reconnect (attempt ${this.#reconnectAttempt})...`
|
|
2906
3003
|
});
|
|
2907
|
-
|
|
3004
|
+
this.#openPegboardWebSocket().catch((err) => {
|
|
3005
|
+
var _a3;
|
|
3006
|
+
(_a3 = this.log) == null ? void 0 : _a3.error({
|
|
3007
|
+
msg: "error during websocket reconnection",
|
|
3008
|
+
error: stringifyError(err)
|
|
3009
|
+
});
|
|
3010
|
+
});
|
|
2908
3011
|
}
|
|
2909
3012
|
}, delay);
|
|
2910
3013
|
}
|
|
2911
|
-
#resendUnacknowledgedEvents(
|
|
3014
|
+
#resendUnacknowledgedEvents() {
|
|
2912
3015
|
var _a;
|
|
2913
|
-
const eventsToResend =
|
|
2914
|
-
|
|
2915
|
-
|
|
3016
|
+
const eventsToResend = [];
|
|
3017
|
+
for (const [_, actor] of this.#actors) {
|
|
3018
|
+
eventsToResend.push(...actor.eventHistory);
|
|
3019
|
+
}
|
|
2916
3020
|
if (eventsToResend.length === 0) return;
|
|
2917
3021
|
(_a = this.log) == null ? void 0 : _a.info({
|
|
2918
3022
|
msg: "resending unacknowledged events",
|
|
2919
|
-
|
|
3023
|
+
count: eventsToResend.length
|
|
2920
3024
|
});
|
|
2921
3025
|
this.__sendToServer({
|
|
2922
3026
|
tag: "ToServerEvents",
|
|
@@ -2946,6 +3050,7 @@ var Runner = class {
|
|
|
2946
3050
|
export {
|
|
2947
3051
|
Runner,
|
|
2948
3052
|
RunnerActor,
|
|
3053
|
+
RunnerShutdownError,
|
|
2949
3054
|
idToStr
|
|
2950
3055
|
};
|
|
2951
3056
|
//# sourceMappingURL=mod.js.map
|