@rivetkit/engine-runner 2.0.26 → 2.0.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivetkit/engine-runner",
3
- "version": "2.0.26",
3
+ "version": "2.0.28",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "import": {
@@ -16,7 +16,7 @@
16
16
  "uuid": "^12.0.0",
17
17
  "pino": "^9.9.5",
18
18
  "ws": "^8.18.3",
19
- "@rivetkit/engine-runner-protocol": "2.0.26"
19
+ "@rivetkit/engine-runner-protocol": "2.0.28"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^22.18.1",
package/src/mod.ts CHANGED
@@ -18,7 +18,7 @@ export { RunnerActor, type ActorConfig };
18
18
  export { idToStr } from "./utils";
19
19
 
20
20
  const KV_EXPIRE: number = 30_000;
21
- const PROTOCOL_VERSION: number = 4;
21
+ const PROTOCOL_VERSION: number = 5;
22
22
 
23
23
  /** Warn once the backlog significantly exceeds the server's ack batch size. */
24
24
  const EVENT_BACKLOG_WARN_THRESHOLD = 10_000;
@@ -291,6 +291,11 @@ export class Runner {
291
291
  }
292
292
 
293
293
  async forceStopActor(actorId: string, generation?: number) {
294
+ this.log?.debug({
295
+ msg: "force stopping actor",
296
+ actorId,
297
+ });
298
+
294
299
  const actor = this.getActor(actorId, generation);
295
300
  if (!actor) return;
296
301
 
@@ -308,12 +313,11 @@ export class Runner {
308
313
  // Close requests after onActorStop so you can send messages over the tunnel
309
314
  this.#tunnel?.closeActiveRequests(actor);
310
315
 
316
+ this.#sendActorStateUpdate(actorId, actor.generation, "stopped");
317
+
311
318
  // Remove actor after stopping in order to ensure that we can still
312
- // call actions on the runner. Do this before sending stopped update in
313
- // order to ensure we don't have duplicate actors.
319
+ // call actions on the runner
314
320
  this.#removeActor(actorId, generation);
315
-
316
- this.#sendActorStateUpdate(actorId, actor.generation, "stopped");
317
321
  }
318
322
 
319
323
  #handleLost() {
@@ -980,6 +984,14 @@ export class Runner {
980
984
  error: stringifyError(err),
981
985
  });
982
986
  });
987
+
988
+ // NOTE: We don't do this for CommandStopActor because the actor will be removed by that call
989
+ // so we cant update the checkpoint
990
+ const actor = this.getActor(
991
+ commandWrapper.checkpoint.actorId,
992
+ commandWrapper.checkpoint.generation,
993
+ );
994
+ if (actor) actor.lastCommandIdx = commandWrapper.checkpoint.index;
983
995
  } else if (commandWrapper.inner.tag === "CommandStopActor") {
984
996
  // Spawn background promise
985
997
  this.#handleCommandStopActor(commandWrapper).catch((err) => {
@@ -992,12 +1004,6 @@ export class Runner {
992
1004
  } else {
993
1005
  unreachable(commandWrapper.inner);
994
1006
  }
995
-
996
- const actor = this.getActor(
997
- commandWrapper.checkpoint.actorId,
998
- commandWrapper.inner.val.generation,
999
- );
1000
- if (actor) actor.lastCommandIdx = commandWrapper.checkpoint.index;
1001
1007
  }
1002
1008
  }
1003
1009
 
@@ -1069,7 +1075,7 @@ export class Runner {
1069
1075
  .val as protocol.CommandStartActor;
1070
1076
 
1071
1077
  const actorId = commandWrapper.checkpoint.actorId;
1072
- const generation = startCommand.generation;
1078
+ const generation = commandWrapper.checkpoint.generation;
1073
1079
  const config = startCommand.config;
1074
1080
 
1075
1081
  const actorConfig: ActorConfig = {
@@ -1150,7 +1156,7 @@ export class Runner {
1150
1156
  .val as protocol.CommandStopActor;
1151
1157
 
1152
1158
  const actorId = commandWrapper.checkpoint.actorId;
1153
- const generation = stopCommand.generation;
1159
+ const generation = commandWrapper.checkpoint.generation;
1154
1160
 
1155
1161
  await this.forceStopActor(actorId, generation);
1156
1162
  }
@@ -1177,14 +1183,13 @@ export class Runner {
1177
1183
  }
1178
1184
 
1179
1185
  const intentEvent: protocol.EventActorIntent = {
1180
- actorId,
1181
- generation,
1182
1186
  intent: actorIntent,
1183
1187
  };
1184
1188
 
1185
1189
  const eventWrapper: protocol.EventWrapper = {
1186
1190
  checkpoint: {
1187
1191
  actorId,
1192
+ generation,
1188
1193
  index: actor.nextEventIdx++,
1189
1194
  },
1190
1195
  inner: {
@@ -1226,14 +1231,13 @@ export class Runner {
1226
1231
  }
1227
1232
 
1228
1233
  const stateUpdateEvent: protocol.EventActorStateUpdate = {
1229
- actorId,
1230
- generation,
1231
1234
  state: actorState,
1232
1235
  };
1233
1236
 
1234
1237
  const eventWrapper: protocol.EventWrapper = {
1235
1238
  checkpoint: {
1236
1239
  actorId,
1240
+ generation,
1237
1241
  index: actor.nextEventIdx++,
1238
1242
  },
1239
1243
  inner: {
@@ -1261,6 +1265,7 @@ export class Runner {
1261
1265
 
1262
1266
  lastCommandCheckpoints.push({
1263
1267
  actorId: actor.actorId,
1268
+ generation: actor.generation,
1264
1269
  index: actor.lastCommandIdx,
1265
1270
  });
1266
1271
  }
@@ -1569,14 +1574,13 @@ export class Runner {
1569
1574
  if (!actor) return;
1570
1575
 
1571
1576
  const alarmEvent: protocol.EventActorSetAlarm = {
1572
- actorId,
1573
- generation: actor.generation,
1574
1577
  alarmTs: alarmTs !== null ? BigInt(alarmTs) : null,
1575
1578
  };
1576
1579
 
1577
1580
  const eventWrapper: protocol.EventWrapper = {
1578
1581
  checkpoint: {
1579
1582
  actorId,
1583
+ generation: actor.generation,
1580
1584
  index: actor.nextEventIdx++,
1581
1585
  },
1582
1586
  inner: {
package/src/stringify.ts CHANGED
@@ -115,7 +115,7 @@ export function stringifyToClientTunnelMessageKind(
115
115
  export function stringifyCommand(command: protocol.Command): string {
116
116
  switch (command.tag) {
117
117
  case "CommandStartActor": {
118
- const { generation, config, hibernatingRequests } =
118
+ const { config, hibernatingRequests } =
119
119
  command.val;
120
120
  const keyStr = config.key === null ? "null" : `"${config.key}"`;
121
121
  const inputStr =
@@ -126,11 +126,10 @@ export function stringifyCommand(command: protocol.Command): string {
126
126
  hibernatingRequests.length > 0
127
127
  ? `[${hibernatingRequests.map((hr) => `{gatewayId: ${idToStr(hr.gatewayId)}, requestId: ${idToStr(hr.requestId)}}`).join(", ")}]`
128
128
  : "[]";
129
- return `CommandStartActor{generation: ${generation}, config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}, hibernatingRequests: ${hibernatingRequestsStr}}`;
129
+ return `CommandStartActor{config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}, hibernatingRequests: ${hibernatingRequestsStr}}`;
130
130
  }
131
131
  case "CommandStopActor": {
132
- const { generation } = command.val;
133
- return `CommandStopActor{generation: ${generation}}`;
132
+ return `CommandStopActor`;
134
133
  }
135
134
  }
136
135
  }
@@ -142,7 +141,7 @@ export function stringifyCommand(command: protocol.Command): string {
142
141
  export function stringifyCommandWrapper(
143
142
  wrapper: protocol.CommandWrapper,
144
143
  ): string {
145
- return `CommandWrapper{actorId: "${wrapper.checkpoint.actorId}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
144
+ return `CommandWrapper{actorId: "${wrapper.checkpoint.actorId}", generation: "${wrapper.checkpoint.generation}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
146
145
  }
147
146
 
148
147
  /**
@@ -152,17 +151,17 @@ export function stringifyCommandWrapper(
152
151
  export function stringifyEvent(event: protocol.Event): string {
153
152
  switch (event.tag) {
154
153
  case "EventActorIntent": {
155
- const { actorId, generation, intent } = event.val;
154
+ const { intent } = event.val;
156
155
  const intentStr =
157
156
  intent.tag === "ActorIntentSleep"
158
157
  ? "Sleep"
159
158
  : intent.tag === "ActorIntentStop"
160
159
  ? "Stop"
161
160
  : "Unknown";
162
- return `EventActorIntent{actorId: "${actorId}", generation: ${generation}, intent: ${intentStr}}`;
161
+ return `EventActorIntent{intent: ${intentStr}}`;
163
162
  }
164
163
  case "EventActorStateUpdate": {
165
- const { actorId, generation, state } = event.val;
164
+ const { state } = event.val;
166
165
  let stateStr: string;
167
166
  if (state.tag === "ActorStateRunning") {
168
167
  stateStr = "Running";
@@ -173,13 +172,13 @@ export function stringifyEvent(event: protocol.Event): string {
173
172
  } else {
174
173
  stateStr = "Unknown";
175
174
  }
176
- return `EventActorStateUpdate{actorId: "${actorId}", generation: ${generation}, state: ${stateStr}}`;
175
+ return `EventActorStateUpdate{state: ${stateStr}}`;
177
176
  }
178
177
  case "EventActorSetAlarm": {
179
- const { actorId, generation, alarmTs } = event.val;
178
+ const { alarmTs } = event.val;
180
179
  const alarmTsStr =
181
180
  alarmTs === null ? "null" : stringifyBigInt(alarmTs);
182
- return `EventActorSetAlarm{actorId: "${actorId}", generation: ${generation}, alarmTs: ${alarmTsStr}}`;
181
+ return `EventActorSetAlarm{alarmTs: ${alarmTsStr}}`;
183
182
  }
184
183
  }
185
184
  }
@@ -189,7 +188,7 @@ export function stringifyEvent(event: protocol.Event): string {
189
188
  * Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
190
189
  */
191
190
  export function stringifyEventWrapper(wrapper: protocol.EventWrapper): string {
192
- return `EventWrapper{actorId: ${wrapper.checkpoint.actorId}, index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
191
+ return `EventWrapper{actorId: ${wrapper.checkpoint.actorId}, generation: "${wrapper.checkpoint.generation}", index: ${stringifyBigInt(wrapper.checkpoint.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
193
192
  }
194
193
 
195
194
  /**