@rivetkit/engine-runner 2.0.25-rc.2 → 2.0.26

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.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,20 +324,20 @@ function stringifyToClientTunnelMessageKind(kind) {
300
324
  function stringifyCommand(command) {
301
325
  switch (command.tag) {
302
326
  case "CommandStartActor": {
303
- const { actorId, generation, config, hibernatingRequests } = command.val;
327
+ const { generation, 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{actorId: "${actorId}", generation: ${generation}, config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}, hibernatingRequests: ${hibernatingRequestsStr}}`;
331
+ return `CommandStartActor{generation: ${generation}, config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}, hibernatingRequests: ${hibernatingRequestsStr}}`;
308
332
  }
309
333
  case "CommandStopActor": {
310
- const { actorId, generation } = command.val;
311
- return `CommandStopActor{actorId: "${actorId}", generation: ${generation}}`;
334
+ const { generation } = command.val;
335
+ return `CommandStopActor{generation: ${generation}}`;
312
336
  }
313
337
  }
314
338
  }
315
339
  function stringifyCommandWrapper(wrapper) {
316
- return `CommandWrapper{index: ${stringifyBigInt(wrapper.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
340
+ return `CommandWrapper{actorId: "${wrapper.checkpoint.actorId}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
317
341
  }
318
342
  function stringifyEvent(event) {
319
343
  switch (event.tag) {
@@ -344,7 +368,7 @@ function stringifyEvent(event) {
344
368
  }
345
369
  }
346
370
  function stringifyEventWrapper(wrapper) {
347
- return `EventWrapper{index: ${stringifyBigInt(wrapper.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
371
+ return `EventWrapper{actorId: ${wrapper.checkpoint.actorId}, index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
348
372
  }
349
373
  function stringifyToServer(message) {
350
374
  switch (message.tag) {
@@ -353,28 +377,27 @@ function stringifyToServer(message) {
353
377
  name,
354
378
  version,
355
379
  totalSlots,
356
- lastCommandIdx,
357
380
  prepopulateActorNames,
358
381
  metadata
359
382
  } = message.val;
360
- const lastCommandIdxStr = lastCommandIdx === null ? "null" : stringifyBigInt(lastCommandIdx);
361
383
  const prepopulateActorNamesStr = prepopulateActorNames === null ? "null" : `Map(${prepopulateActorNames.size})`;
362
384
  const metadataStr = metadata === null ? "null" : `"${metadata}"`;
363
- return `ToServerInit{name: "${name}", version: ${version}, totalSlots: ${totalSlots}, lastCommandIdx: ${lastCommandIdxStr}, prepopulateActorNames: ${prepopulateActorNamesStr}, metadata: ${metadataStr}}`;
385
+ return `ToServerInit{name: "${name}", version: ${version}, totalSlots: ${totalSlots}, prepopulateActorNames: ${prepopulateActorNamesStr}, metadata: ${metadataStr}}`;
364
386
  }
365
387
  case "ToServerEvents": {
366
388
  const events = message.val;
367
389
  return `ToServerEvents{count: ${events.length}, events: [${events.map((e) => stringifyEventWrapper(e)).join(", ")}]}`;
368
390
  }
369
391
  case "ToServerAckCommands": {
370
- const { lastCommandIdx } = message.val;
371
- return `ToServerAckCommands{lastCommandIdx: ${stringifyBigInt(lastCommandIdx)}}`;
392
+ const { lastCommandCheckpoints } = message.val;
393
+ const checkpointsStr = lastCommandCheckpoints.length > 0 ? `[${lastCommandCheckpoints.map((cp) => `{actorId: "${cp.actorId}", index: ${stringifyBigInt(cp.index)}}`).join(", ")}]` : "[]";
394
+ return `ToServerAckCommands{lastCommandCheckpoints: ${checkpointsStr}}`;
372
395
  }
373
396
  case "ToServerStopping":
374
397
  return "ToServerStopping";
375
- case "ToServerPing": {
398
+ case "ToServerPong": {
376
399
  const { ts } = message.val;
377
- return `ToServerPing{ts: ${stringifyBigInt(ts)}}`;
400
+ return `ToServerPong{ts: ${stringifyBigInt(ts)}}`;
378
401
  }
379
402
  case "ToServerKvRequest": {
380
403
  const { actorId, requestId, data } = message.val;
@@ -390,19 +413,21 @@ function stringifyToServer(message) {
390
413
  function stringifyToClient(message) {
391
414
  switch (message.tag) {
392
415
  case "ToClientInit": {
393
- const { runnerId, lastEventIdx, metadata } = message.val;
416
+ const { runnerId, metadata } = message.val;
394
417
  const metadataStr = `{runnerLostThreshold: ${stringifyBigInt(metadata.runnerLostThreshold)}}`;
395
- return `ToClientInit{runnerId: "${runnerId}", lastEventIdx: ${stringifyBigInt(lastEventIdx)}, metadata: ${metadataStr}}`;
418
+ return `ToClientInit{runnerId: "${runnerId}", metadata: ${metadataStr}}`;
396
419
  }
397
- case "ToClientClose":
398
- return "ToClientClose";
420
+ case "ToClientPing":
421
+ const { ts } = message.val;
422
+ return `ToClientPing{ts: ${stringifyBigInt(ts)}}`;
399
423
  case "ToClientCommands": {
400
424
  const commands = message.val;
401
425
  return `ToClientCommands{count: ${commands.length}, commands: [${commands.map((c) => stringifyCommandWrapper(c)).join(", ")}]}`;
402
426
  }
403
427
  case "ToClientAckEvents": {
404
- const { lastEventIdx } = message.val;
405
- return `ToClientAckEvents{lastEventIdx: ${stringifyBigInt(lastEventIdx)}}`;
428
+ const { lastEventCheckpoints } = message.val;
429
+ const checkpointsStr = lastEventCheckpoints.length > 0 ? `[${lastEventCheckpoints.map((cp) => `{actorId: "${cp.actorId}", index: ${stringifyBigInt(cp.index)}}`).join(", ")}]` : "[]";
430
+ return `ToClientAckEvents{lastEventCheckpoints: ${checkpointsStr}}`;
406
431
  }
407
432
  case "ToClientKvResponse": {
408
433
  const { requestId, data } = message.val;
@@ -893,11 +918,6 @@ var WebSocketTunnelAdapter = class {
893
918
  };
894
919
 
895
920
  // src/tunnel.ts
896
- var RunnerShutdownError = class extends Error {
897
- constructor() {
898
- super("Runner shut down");
899
- }
900
- };
901
921
  var Tunnel = class {
902
922
  #runner;
903
923
  /** Maps request IDs to actor IDs for lookup */
@@ -1019,7 +1039,7 @@ var Tunnel = class {
1019
1039
  (_a2 = this.log) == null ? void 0 : _a2.error({
1020
1040
  msg: "error creating websocket during restore",
1021
1041
  requestId: requestIdStr,
1022
- err
1042
+ error: stringifyError(err)
1023
1043
  });
1024
1044
  this.#sendMessage(gatewayId, requestId, {
1025
1045
  tag: "ToServerWebSocketClose",
@@ -1068,7 +1088,7 @@ var Tunnel = class {
1068
1088
  (_a2 = this.log) == null ? void 0 : _a2.error({
1069
1089
  msg: "error creating stale websocket during restore",
1070
1090
  requestId: requestIdStr,
1071
- err
1091
+ error: stringifyError(err)
1072
1092
  });
1073
1093
  });
1074
1094
  backgroundOperations.push(cleanupOperation);
@@ -1348,8 +1368,6 @@ var Tunnel = class {
1348
1368
  message.messageKind.val
1349
1369
  );
1350
1370
  break;
1351
- case "DeprecatedTunnelAck":
1352
- break;
1353
1371
  default:
1354
1372
  unreachable(message.messageKind);
1355
1373
  }
@@ -1738,10 +1756,14 @@ async function importWebSocket() {
1738
1756
 
1739
1757
  // src/mod.ts
1740
1758
  var KV_EXPIRE = 3e4;
1741
- var PROTOCOL_VERSION = 3;
1742
- var RUNNER_PING_INTERVAL = 3e3;
1759
+ var PROTOCOL_VERSION = 4;
1743
1760
  var EVENT_BACKLOG_WARN_THRESHOLD = 1e4;
1744
1761
  var SIGNAL_HANDLERS = [];
1762
+ var RunnerShutdownError = class extends Error {
1763
+ constructor() {
1764
+ super("Runner shut down");
1765
+ }
1766
+ };
1745
1767
  var Runner = class {
1746
1768
  #config;
1747
1769
  get config() {
@@ -1751,9 +1773,6 @@ var Runner = class {
1751
1773
  // WebSocket
1752
1774
  __pegboardWebSocket;
1753
1775
  runnerId;
1754
- #lastCommandIdx = -1;
1755
- #pingLoop;
1756
- #nextEventIdx = 0n;
1757
1776
  #started = false;
1758
1777
  #shutdown = false;
1759
1778
  #shuttingDown = false;
@@ -1763,7 +1782,6 @@ var Runner = class {
1763
1782
  #runnerLostThreshold;
1764
1783
  #runnerLostTimeout;
1765
1784
  // Event storage for resending
1766
- #eventHistory = [];
1767
1785
  #eventBacklogWarned = false;
1768
1786
  // Command acknowledgment
1769
1787
  #ackInterval;
@@ -1794,7 +1812,15 @@ var Runner = class {
1794
1812
  this.#config = config;
1795
1813
  if (this.#config.logger) setLogger(this.#config.logger);
1796
1814
  this.#kvCleanupInterval = setInterval(() => {
1797
- this.#cleanupOldKvRequests();
1815
+ var _a;
1816
+ try {
1817
+ this.#cleanupOldKvRequests();
1818
+ } catch (err) {
1819
+ (_a = this.log) == null ? void 0 : _a.error({
1820
+ msg: "error cleaning up kv requests",
1821
+ error: stringifyError(err)
1822
+ });
1823
+ }
1798
1824
  }, 15e3);
1799
1825
  }
1800
1826
  // MARK: Manage actors
@@ -1821,14 +1847,28 @@ var Runner = class {
1821
1847
  this.#removeActor(actorId, generation);
1822
1848
  this.#sendActorStateUpdate(actorId, actor.generation, "stopped");
1823
1849
  }
1824
- #stopAllActors() {
1850
+ #handleLost() {
1825
1851
  var _a;
1826
1852
  (_a = this.log) == null ? void 0 : _a.info({
1827
- msg: "stopping all actors due to runner lost threshold exceeded"
1853
+ msg: "stopping all actors due to runner lost threshold"
1828
1854
  });
1855
+ for (const [_, request] of this.#kvRequests.entries()) {
1856
+ request.reject(new RunnerShutdownError());
1857
+ }
1858
+ this.#kvRequests.clear();
1859
+ this.#stopAllActors();
1860
+ }
1861
+ #stopAllActors() {
1829
1862
  const actorIds = Array.from(this.#actors.keys());
1830
1863
  for (const actorId of actorIds) {
1831
- this.forceStopActor(actorId);
1864
+ this.forceStopActor(actorId).catch((err) => {
1865
+ var _a;
1866
+ (_a = this.log) == null ? void 0 : _a.error({
1867
+ msg: "error stopping actor",
1868
+ actorId,
1869
+ error: stringifyError(err)
1870
+ });
1871
+ });
1832
1872
  }
1833
1873
  }
1834
1874
  getActor(actorId, generation) {
@@ -1956,10 +1996,6 @@ var Runner = class {
1956
1996
  clearTimeout(this.#runnerLostTimeout);
1957
1997
  this.#runnerLostTimeout = void 0;
1958
1998
  }
1959
- if (this.#pingLoop) {
1960
- clearInterval(this.#pingLoop);
1961
- this.#pingLoop = void 0;
1962
- }
1963
1999
  if (this.#ackInterval) {
1964
2000
  clearInterval(this.#ackInterval);
1965
2001
  this.#ackInterval = void 0;
@@ -2167,7 +2203,6 @@ var Runner = class {
2167
2203
  name: this.#config.runnerName,
2168
2204
  version: this.#config.version,
2169
2205
  totalSlots: this.#config.totalSlots,
2170
- lastCommandIdx: this.#lastCommandIdx >= 0 ? BigInt(this.#lastCommandIdx) : null,
2171
2206
  prepopulateActorNames: new Map(
2172
2207
  Object.entries(this.#config.prepopulateActorNames).map(
2173
2208
  ([name, data]) => [
@@ -2182,39 +2217,29 @@ var Runner = class {
2182
2217
  tag: "ToServerInit",
2183
2218
  val: init
2184
2219
  });
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
2220
  const ackInterval = 5 * 60 * 1e3;
2203
2221
  const ackLoop = setInterval(() => {
2204
- var _a3;
2205
- if (ws.readyState === 1) {
2206
- this.#sendCommandAcknowledgment();
2207
- } else {
2208
- clearInterval(ackLoop);
2209
- (_a3 = this.log) == null ? void 0 : _a3.info({
2210
- msg: "WebSocket not open, stopping ack loop"
2222
+ var _a3, _b2;
2223
+ try {
2224
+ if (ws.readyState === 1) {
2225
+ this.#sendCommandAcknowledgment();
2226
+ } else {
2227
+ clearInterval(ackLoop);
2228
+ (_a3 = this.log) == null ? void 0 : _a3.info({
2229
+ msg: "WebSocket not open, stopping ack loop"
2230
+ });
2231
+ }
2232
+ } catch (err) {
2233
+ (_b2 = this.log) == null ? void 0 : _b2.error({
2234
+ msg: "error in command acknowledgment loop",
2235
+ error: stringifyError(err)
2211
2236
  });
2212
2237
  }
2213
2238
  }, ackInterval);
2214
2239
  this.#ackInterval = ackLoop;
2215
2240
  });
2216
2241
  ws.addEventListener("message", async (ev) => {
2217
- var _a2, _b, _c, _d, _e, _f;
2242
+ var _a2, _b, _c, _d, _e;
2218
2243
  let buf;
2219
2244
  if (ev.data instanceof Blob) {
2220
2245
  buf = new Uint8Array(await ev.data.arrayBuffer());
@@ -2232,16 +2257,15 @@ var Runner = class {
2232
2257
  const init = message.val;
2233
2258
  if (this.runnerId !== init.runnerId) {
2234
2259
  this.runnerId = init.runnerId;
2235
- this.#eventHistory.length = 0;
2260
+ this.#stopAllActors();
2236
2261
  }
2237
2262
  this.#runnerLostThreshold = ((_b = init.metadata) == null ? void 0 : _b.runnerLostThreshold) ? Number(init.metadata.runnerLostThreshold) : void 0;
2238
2263
  (_c = this.log) == null ? void 0 : _c.info({
2239
2264
  msg: "received init",
2240
- lastEventIdx: init.lastEventIdx,
2241
2265
  runnerLostThreshold: this.#runnerLostThreshold
2242
2266
  });
2243
2267
  this.#processUnsentKvRequests();
2244
- this.#resendUnacknowledgedEvents(init.lastEventIdx);
2268
+ this.#resendUnacknowledgedEvents();
2245
2269
  (_d = this.#tunnel) == null ? void 0 : _d.resendBufferedEvents();
2246
2270
  this.#config.onConnected();
2247
2271
  } else if (message.tag === "ToClientCommands") {
@@ -2253,10 +2277,20 @@ var Runner = class {
2253
2277
  const kvResponse = message.val;
2254
2278
  this.#handleKvResponse(kvResponse);
2255
2279
  } else if (message.tag === "ToClientTunnelMessage") {
2256
- (_e = this.#tunnel) == null ? void 0 : _e.handleTunnelMessage(message.val);
2257
- } else if (message.tag === "ToClientClose") {
2258
- (_f = this.#tunnel) == null ? void 0 : _f.shutdown();
2259
- ws.close(1e3, "manual closure");
2280
+ (_e = this.#tunnel) == null ? void 0 : _e.handleTunnelMessage(message.val).catch((err) => {
2281
+ var _a3;
2282
+ (_a3 = this.log) == null ? void 0 : _a3.error({
2283
+ msg: "error handling tunnel message",
2284
+ error: stringifyError(err)
2285
+ });
2286
+ });
2287
+ } else if (message.tag === "ToClientPing") {
2288
+ this.__sendToServer({
2289
+ tag: "ToServerPong",
2290
+ val: {
2291
+ ts: message.val.ts
2292
+ }
2293
+ });
2260
2294
  } else {
2261
2295
  unreachable(message);
2262
2296
  }
@@ -2273,7 +2307,15 @@ var Runner = class {
2273
2307
  seconds: this.#runnerLostThreshold / 1e3
2274
2308
  });
2275
2309
  this.#runnerLostTimeout = setTimeout(() => {
2276
- this.#stopAllActors();
2310
+ var _a3;
2311
+ try {
2312
+ this.#handleLost();
2313
+ } catch (err) {
2314
+ (_a3 = this.log) == null ? void 0 : _a3.error({
2315
+ msg: "error handling runner lost",
2316
+ error: stringifyError(err)
2317
+ });
2318
+ }
2277
2319
  }, this.#runnerLostThreshold);
2278
2320
  }
2279
2321
  this.#scheduleReconnect();
@@ -2299,10 +2341,6 @@ var Runner = class {
2299
2341
  }
2300
2342
  this.#config.onDisconnected(ev.code, ev.reason);
2301
2343
  }
2302
- if (this.#pingLoop) {
2303
- clearInterval(this.#pingLoop);
2304
- this.#pingLoop = void 0;
2305
- }
2306
2344
  if (this.#ackInterval) {
2307
2345
  clearInterval(this.#ackInterval);
2308
2346
  this.#ackInterval = void 0;
@@ -2314,7 +2352,15 @@ var Runner = class {
2314
2352
  seconds: this.#runnerLostThreshold / 1e3
2315
2353
  });
2316
2354
  this.#runnerLostTimeout = setTimeout(() => {
2317
- this.#stopAllActors();
2355
+ var _a3;
2356
+ try {
2357
+ this.#handleLost();
2358
+ } catch (err) {
2359
+ (_a3 = this.log) == null ? void 0 : _a3.error({
2360
+ msg: "error handling runner lost",
2361
+ error: stringifyError(err)
2362
+ });
2363
+ }
2318
2364
  }, this.#runnerLostThreshold);
2319
2365
  }
2320
2366
  this.#scheduleReconnect();
@@ -2329,43 +2375,75 @@ var Runner = class {
2329
2375
  });
2330
2376
  for (const commandWrapper of commands) {
2331
2377
  if (commandWrapper.inner.tag === "CommandStartActor") {
2332
- this.#handleCommandStartActor(commandWrapper);
2378
+ this.#handleCommandStartActor(commandWrapper).catch((err) => {
2379
+ var _a2;
2380
+ (_a2 = this.log) == null ? void 0 : _a2.error({
2381
+ msg: "error handling start actor command",
2382
+ actorId: commandWrapper.checkpoint.actorId,
2383
+ error: stringifyError(err)
2384
+ });
2385
+ });
2333
2386
  } else if (commandWrapper.inner.tag === "CommandStopActor") {
2334
- this.#handleCommandStopActor(commandWrapper);
2387
+ this.#handleCommandStopActor(commandWrapper).catch((err) => {
2388
+ var _a2;
2389
+ (_a2 = this.log) == null ? void 0 : _a2.error({
2390
+ msg: "error handling stop actor command",
2391
+ actorId: commandWrapper.checkpoint.actorId,
2392
+ error: stringifyError(err)
2393
+ });
2394
+ });
2335
2395
  } else {
2336
2396
  unreachable(commandWrapper.inner);
2337
2397
  }
2338
- this.#lastCommandIdx = Number(commandWrapper.index);
2398
+ const actor = this.getActor(
2399
+ commandWrapper.checkpoint.actorId,
2400
+ commandWrapper.inner.val.generation
2401
+ );
2402
+ if (actor) actor.lastCommandIdx = commandWrapper.checkpoint.index;
2339
2403
  }
2340
2404
  }
2341
2405
  #handleAckEvents(ack) {
2342
2406
  var _a;
2343
- const lastAckedIdx = ack.lastEventIdx;
2344
- const originalLength = this.#eventHistory.length;
2345
- this.#eventHistory = this.#eventHistory.filter(
2346
- (event) => event.index > lastAckedIdx
2407
+ let originalTotalEvents = Array.from(this.#actors).reduce(
2408
+ (s, [_, actor]) => s + actor.eventHistory.length,
2409
+ 0
2410
+ );
2411
+ for (const [_, actor] of this.#actors) {
2412
+ let checkpoint = ack.lastEventCheckpoints.find(
2413
+ (x) => x.actorId == actor.actorId
2414
+ );
2415
+ if (checkpoint) actor.handleAckEvents(checkpoint.index);
2416
+ }
2417
+ const totalEvents = Array.from(this.#actors).reduce(
2418
+ (s, [_, actor]) => s + actor.eventHistory.length,
2419
+ 0
2347
2420
  );
2348
- const prunedCount = originalLength - this.#eventHistory.length;
2421
+ const prunedCount = originalTotalEvents - totalEvents;
2349
2422
  if (prunedCount > 0) {
2350
2423
  (_a = this.log) == null ? void 0 : _a.info({
2351
2424
  msg: "pruned acknowledged events",
2352
- lastAckedIdx: lastAckedIdx.toString(),
2353
2425
  prunedCount
2354
2426
  });
2355
2427
  }
2356
- if (this.#eventHistory.length <= EVENT_BACKLOG_WARN_THRESHOLD) {
2428
+ if (totalEvents <= EVENT_BACKLOG_WARN_THRESHOLD) {
2357
2429
  this.#eventBacklogWarned = false;
2358
2430
  }
2359
2431
  }
2360
2432
  /** Track events to send to the server in case we need to resend it on disconnect. */
2361
2433
  #recordEvent(eventWrapper) {
2362
2434
  var _a;
2363
- this.#eventHistory.push(eventWrapper);
2364
- if (this.#eventHistory.length > EVENT_BACKLOG_WARN_THRESHOLD && !this.#eventBacklogWarned) {
2435
+ const actor = this.getActor(eventWrapper.checkpoint.actorId);
2436
+ if (!actor) return;
2437
+ actor.recordEvent(eventWrapper);
2438
+ let totalEvents = Array.from(this.#actors).reduce(
2439
+ (s, [_, actor2]) => s + actor2.eventHistory.length,
2440
+ 0
2441
+ );
2442
+ if (totalEvents > EVENT_BACKLOG_WARN_THRESHOLD && !this.#eventBacklogWarned) {
2365
2443
  this.#eventBacklogWarned = true;
2366
2444
  (_a = this.log) == null ? void 0 : _a.warn({
2367
2445
  msg: "unacknowledged event backlog exceeds threshold",
2368
- backlogSize: this.#eventHistory.length,
2446
+ backlogSize: totalEvents,
2369
2447
  threshold: EVENT_BACKLOG_WARN_THRESHOLD
2370
2448
  });
2371
2449
  }
@@ -2374,7 +2452,7 @@ var Runner = class {
2374
2452
  var _a, _b, _c, _d;
2375
2453
  if (!this.#tunnel) throw new Error("missing tunnel on actor start");
2376
2454
  const startCommand = commandWrapper.inner.val;
2377
- const actorId = startCommand.actorId;
2455
+ const actorId = commandWrapper.checkpoint.actorId;
2378
2456
  const generation = startCommand.generation;
2379
2457
  const config = startCommand.config;
2380
2458
  const actorConfig = {
@@ -2433,11 +2511,13 @@ var Runner = class {
2433
2511
  }
2434
2512
  async #handleCommandStopActor(commandWrapper) {
2435
2513
  const stopCommand = commandWrapper.inner.val;
2436
- const actorId = stopCommand.actorId;
2514
+ const actorId = commandWrapper.checkpoint.actorId;
2437
2515
  const generation = stopCommand.generation;
2438
2516
  await this.forceStopActor(actorId, generation);
2439
2517
  }
2440
2518
  #sendActorIntent(actorId, generation, intentType) {
2519
+ const actor = this.getActor(actorId, generation);
2520
+ if (!actor) return;
2441
2521
  let actorIntent;
2442
2522
  if (intentType === "sleep") {
2443
2523
  actorIntent = { tag: "ActorIntentSleep", val: null };
@@ -2454,9 +2534,11 @@ var Runner = class {
2454
2534
  generation,
2455
2535
  intent: actorIntent
2456
2536
  };
2457
- const eventIndex = this.#nextEventIdx++;
2458
2537
  const eventWrapper = {
2459
- index: eventIndex,
2538
+ checkpoint: {
2539
+ actorId,
2540
+ index: actor.nextEventIdx++
2541
+ },
2460
2542
  inner: {
2461
2543
  tag: "EventActorIntent",
2462
2544
  val: intentEvent
@@ -2469,6 +2551,8 @@ var Runner = class {
2469
2551
  });
2470
2552
  }
2471
2553
  #sendActorStateUpdate(actorId, generation, stateType) {
2554
+ const actor = this.getActor(actorId, generation);
2555
+ if (!actor) return;
2472
2556
  let actorState;
2473
2557
  if (stateType === "running") {
2474
2558
  actorState = { tag: "ActorStateRunning", val: null };
@@ -2488,9 +2572,11 @@ var Runner = class {
2488
2572
  generation,
2489
2573
  state: actorState
2490
2574
  };
2491
- const eventIndex = this.#nextEventIdx++;
2492
2575
  const eventWrapper = {
2493
- index: eventIndex,
2576
+ checkpoint: {
2577
+ actorId,
2578
+ index: actor.nextEventIdx++
2579
+ },
2494
2580
  inner: {
2495
2581
  tag: "EventActorStateUpdate",
2496
2582
  val: stateUpdateEvent
@@ -2503,13 +2589,20 @@ var Runner = class {
2503
2589
  });
2504
2590
  }
2505
2591
  #sendCommandAcknowledgment() {
2506
- if (this.#lastCommandIdx < 0) {
2507
- return;
2592
+ const lastCommandCheckpoints = [];
2593
+ for (const [_, actor] of this.#actors) {
2594
+ if (actor.lastCommandIdx < 0) {
2595
+ continue;
2596
+ }
2597
+ lastCommandCheckpoints.push({
2598
+ actorId: actor.actorId,
2599
+ index: actor.lastCommandIdx
2600
+ });
2508
2601
  }
2509
2602
  this.__sendToServer({
2510
2603
  tag: "ToServerAckCommands",
2511
2604
  val: {
2512
- lastCommandIdx: BigInt(this.#lastCommandIdx)
2605
+ lastCommandCheckpoints
2513
2606
  }
2514
2607
  });
2515
2608
  }
@@ -2743,9 +2836,11 @@ var Runner = class {
2743
2836
  generation: actor.generation,
2744
2837
  alarmTs: alarmTs !== null ? BigInt(alarmTs) : null
2745
2838
  };
2746
- const eventIndex = this.#nextEventIdx++;
2747
2839
  const eventWrapper = {
2748
- index: eventIndex,
2840
+ checkpoint: {
2841
+ actorId,
2842
+ index: actor.nextEventIdx++
2843
+ },
2749
2844
  inner: {
2750
2845
  tag: "EventActorSetAlarm",
2751
2846
  val: alarmEvent
@@ -2872,7 +2967,8 @@ var Runner = class {
2872
2967
  const data = protocol.encodeToServerlessServer({
2873
2968
  tag: "ToServerlessServerInit",
2874
2969
  val: {
2875
- runnerId: this.runnerId
2970
+ runnerId: this.runnerId,
2971
+ runnerProtocolVersion: PROTOCOL_VERSION
2876
2972
  }
2877
2973
  });
2878
2974
  const buffer = Buffer.alloc(data.length + 2);
@@ -2897,26 +2993,33 @@ var Runner = class {
2897
2993
  (_b = this.log) == null ? void 0 : _b.debug({
2898
2994
  msg: `Scheduling reconnect attempt ${this.#reconnectAttempt + 1} in ${delay}ms`
2899
2995
  });
2900
- this.#reconnectTimeout = setTimeout(async () => {
2996
+ this.#reconnectTimeout = setTimeout(() => {
2901
2997
  var _a2;
2902
2998
  if (!this.#shutdown) {
2903
2999
  this.#reconnectAttempt++;
2904
3000
  (_a2 = this.log) == null ? void 0 : _a2.debug({
2905
3001
  msg: `Attempting to reconnect (attempt ${this.#reconnectAttempt})...`
2906
3002
  });
2907
- await this.#openPegboardWebSocket();
3003
+ this.#openPegboardWebSocket().catch((err) => {
3004
+ var _a3;
3005
+ (_a3 = this.log) == null ? void 0 : _a3.error({
3006
+ msg: "error during websocket reconnection",
3007
+ error: stringifyError(err)
3008
+ });
3009
+ });
2908
3010
  }
2909
3011
  }, delay);
2910
3012
  }
2911
- #resendUnacknowledgedEvents(lastEventIdx) {
3013
+ #resendUnacknowledgedEvents() {
2912
3014
  var _a;
2913
- const eventsToResend = this.#eventHistory.filter(
2914
- (event) => event.index > lastEventIdx
2915
- );
3015
+ const eventsToResend = [];
3016
+ for (const [_, actor] of this.#actors) {
3017
+ eventsToResend.push(...actor.eventHistory);
3018
+ }
2916
3019
  if (eventsToResend.length === 0) return;
2917
3020
  (_a = this.log) == null ? void 0 : _a.info({
2918
3021
  msg: "resending unacknowledged events",
2919
- fromIndex: lastEventIdx + 1n
3022
+ count: eventsToResend.length
2920
3023
  });
2921
3024
  this.__sendToServer({
2922
3025
  tag: "ToServerEvents",
@@ -2946,6 +3049,7 @@ var Runner = class {
2946
3049
  export {
2947
3050
  Runner,
2948
3051
  RunnerActor,
3052
+ RunnerShutdownError,
2949
3053
  idToStr
2950
3054
  };
2951
3055
  //# sourceMappingURL=mod.js.map