@rivetkit/engine-runner 2.0.24-rc.1 → 2.0.24

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.24-rc.1",
3
+ "version": "2.0.24",
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.24-rc.1"
19
+ "@rivetkit/engine-runner-protocol": "2.0.24"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^22.18.1",
package/src/actor.ts ADDED
@@ -0,0 +1,196 @@
1
+ import type * as protocol from "@rivetkit/engine-runner-protocol";
2
+ import { logger } from "./log";
3
+ import type { PendingRequest } from "./tunnel";
4
+ import { arraysEqual, idToStr, promiseWithResolvers } from "./utils";
5
+ import type { WebSocketTunnelAdapter } from "./websocket-tunnel-adapter";
6
+
7
+ export interface ActorConfig {
8
+ name: string;
9
+ key: string | null;
10
+ createTs: bigint;
11
+ input: Uint8Array | null;
12
+ }
13
+
14
+ export class RunnerActor {
15
+ actorId: string;
16
+ generation: number;
17
+ config: ActorConfig;
18
+ pendingRequests: Array<{
19
+ gatewayId: protocol.GatewayId;
20
+ requestId: protocol.RequestId;
21
+ request: PendingRequest;
22
+ }> = [];
23
+ webSockets: Array<{
24
+ gatewayId: protocol.GatewayId;
25
+ requestId: protocol.RequestId;
26
+ ws: WebSocketTunnelAdapter;
27
+ }> = [];
28
+ actorStartPromise: ReturnType<typeof promiseWithResolvers<void>>;
29
+
30
+ /**
31
+ * If restoreHibernatingRequests has been called. This is used to assert
32
+ * that the caller is implemented correctly.
33
+ **/
34
+ hibernationRestored: boolean = false;
35
+
36
+ constructor(
37
+ actorId: string,
38
+ generation: number,
39
+ config: ActorConfig,
40
+ /**
41
+ * List of hibernating requests provided by the gateway on actor start.
42
+ * This represents the WebSocket connections that the gateway knows about.
43
+ **/
44
+ public hibernatingRequests: readonly protocol.HibernatingRequest[],
45
+ ) {
46
+ this.actorId = actorId;
47
+ this.generation = generation;
48
+ this.config = config;
49
+ this.actorStartPromise = promiseWithResolvers();
50
+ }
51
+
52
+ // Pending request methods
53
+ getPendingRequest(
54
+ gatewayId: protocol.GatewayId,
55
+ requestId: protocol.RequestId,
56
+ ): PendingRequest | undefined {
57
+ return this.pendingRequests.find(
58
+ (entry) =>
59
+ arraysEqual(entry.gatewayId, gatewayId) &&
60
+ arraysEqual(entry.requestId, requestId),
61
+ )?.request;
62
+ }
63
+
64
+ createPendingRequest(
65
+ gatewayId: protocol.GatewayId,
66
+ requestId: protocol.RequestId,
67
+ clientMessageIndex: number,
68
+ ) {
69
+ const exists =
70
+ this.getPendingRequest(gatewayId, requestId) !== undefined;
71
+ if (exists) {
72
+ logger()?.warn({
73
+ msg: "attempting to set pending request twice, replacing existing",
74
+ gatewayId: idToStr(gatewayId),
75
+ requestId: idToStr(requestId),
76
+ });
77
+ // Delete existing pending request before adding the new one
78
+ this.deletePendingRequest(gatewayId, requestId);
79
+ }
80
+ this.pendingRequests.push({
81
+ gatewayId,
82
+ requestId,
83
+ request: {
84
+ resolve: () => {},
85
+ reject: () => {},
86
+ actorId: this.actorId,
87
+ gatewayId: gatewayId,
88
+ requestId: requestId,
89
+ clientMessageIndex,
90
+ },
91
+ });
92
+ logger()?.debug({
93
+ msg: "added pending request",
94
+ gatewayId: idToStr(gatewayId),
95
+ requestId: idToStr(requestId),
96
+ length: this.pendingRequests.length,
97
+ });
98
+ }
99
+
100
+ createPendingRequestWithStreamController(
101
+ gatewayId: protocol.GatewayId,
102
+ requestId: protocol.RequestId,
103
+ clientMessageIndex: number,
104
+ streamController: ReadableStreamDefaultController<Uint8Array>,
105
+ ) {
106
+ const exists =
107
+ this.getPendingRequest(gatewayId, requestId) !== undefined;
108
+ if (exists) {
109
+ logger()?.warn({
110
+ msg: "attempting to set pending request twice, replacing existing",
111
+ gatewayId: idToStr(gatewayId),
112
+ requestId: idToStr(requestId),
113
+ });
114
+ // Delete existing pending request before adding the new one
115
+ this.deletePendingRequest(gatewayId, requestId);
116
+ }
117
+ this.pendingRequests.push({
118
+ gatewayId,
119
+ requestId,
120
+ request: {
121
+ resolve: () => {},
122
+ reject: () => {},
123
+ actorId: this.actorId,
124
+ gatewayId: gatewayId,
125
+ requestId: requestId,
126
+ clientMessageIndex,
127
+ streamController,
128
+ },
129
+ });
130
+ logger()?.debug({
131
+ msg: "added pending request with stream controller",
132
+ gatewayId: idToStr(gatewayId),
133
+ requestId: idToStr(requestId),
134
+ length: this.pendingRequests.length,
135
+ });
136
+ }
137
+
138
+ deletePendingRequest(
139
+ gatewayId: protocol.GatewayId,
140
+ requestId: protocol.RequestId,
141
+ ) {
142
+ const index = this.pendingRequests.findIndex(
143
+ (entry) =>
144
+ arraysEqual(entry.gatewayId, gatewayId) &&
145
+ arraysEqual(entry.requestId, requestId),
146
+ );
147
+ if (index !== -1) {
148
+ this.pendingRequests.splice(index, 1);
149
+ logger()?.debug({
150
+ msg: "removed pending request",
151
+ gatewayId: idToStr(gatewayId),
152
+ requestId: idToStr(requestId),
153
+ length: this.pendingRequests.length,
154
+ });
155
+ }
156
+ }
157
+
158
+ // WebSocket methods
159
+ getWebSocket(
160
+ gatewayId: protocol.GatewayId,
161
+ requestId: protocol.RequestId,
162
+ ): WebSocketTunnelAdapter | undefined {
163
+ return this.webSockets.find(
164
+ (entry) =>
165
+ arraysEqual(entry.gatewayId, gatewayId) &&
166
+ arraysEqual(entry.requestId, requestId),
167
+ )?.ws;
168
+ }
169
+
170
+ setWebSocket(
171
+ gatewayId: protocol.GatewayId,
172
+ requestId: protocol.RequestId,
173
+ ws: WebSocketTunnelAdapter,
174
+ ) {
175
+ const exists = this.getWebSocket(gatewayId, requestId) !== undefined;
176
+ if (exists) {
177
+ logger()?.warn({ msg: "attempting to set websocket twice" });
178
+ return;
179
+ }
180
+ this.webSockets.push({ gatewayId, requestId, ws });
181
+ }
182
+
183
+ deleteWebSocket(
184
+ gatewayId: protocol.GatewayId,
185
+ requestId: protocol.RequestId,
186
+ ) {
187
+ const index = this.webSockets.findIndex(
188
+ (entry) =>
189
+ arraysEqual(entry.gatewayId, gatewayId) &&
190
+ arraysEqual(entry.requestId, requestId),
191
+ );
192
+ if (index !== -1) {
193
+ this.webSockets.splice(index, 1);
194
+ }
195
+ }
196
+ }