rivetkit 2.3.0-rc.8 → 2.3.0-rc.9
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/browser/client.d.ts +8 -37
- package/dist/browser/client.js +34 -64
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.js +3 -4
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/actor/errors.cjs +2 -2
- package/dist/tsup/actor/errors.js +1 -1
- package/dist/tsup/agent-os/index.cjs +5 -7
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +5 -26
- package/dist/tsup/agent-os/index.d.ts +5 -26
- package/dist/tsup/agent-os/index.js +5 -7
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-OT7FF6GB.cjs → chunk-4CGA6QJO.cjs} +4 -4
- package/dist/tsup/{chunk-OT7FF6GB.cjs.map → chunk-4CGA6QJO.cjs.map} +1 -1
- package/dist/tsup/{chunk-4BPKKZJO.cjs → chunk-4WPEZBK4.cjs} +8 -8
- package/dist/tsup/{chunk-4BPKKZJO.cjs.map → chunk-4WPEZBK4.cjs.map} +1 -1
- package/dist/tsup/{chunk-AWTPTUQ7.cjs → chunk-CPA4Y3RG.cjs} +10 -10
- package/dist/tsup/chunk-CPA4Y3RG.cjs.map +1 -0
- package/dist/tsup/{chunk-EMFKMVJR.js → chunk-F3Q5BFQ6.js} +34 -10
- package/dist/tsup/chunk-F3Q5BFQ6.js.map +1 -0
- package/dist/tsup/{chunk-7HLFSAJP.cjs → chunk-GVTOE34S.cjs} +193 -169
- package/dist/tsup/chunk-GVTOE34S.cjs.map +1 -0
- package/dist/tsup/{chunk-D3T3ZBSY.js → chunk-H37XQU3I.js} +2 -2
- package/dist/tsup/{chunk-4JU3IPG2.js → chunk-H7P7WR2Y.js} +3 -3
- package/dist/tsup/{chunk-TMLOKTRB.js → chunk-KIWH5H3K.js} +3 -3
- package/dist/tsup/chunk-KIWH5H3K.js.map +1 -0
- package/dist/tsup/{chunk-VUGENVIK.js → chunk-KJTA3ATT.js} +2 -2
- package/dist/tsup/{chunk-6TQSSJ4F.cjs → chunk-MALSPBAF.cjs} +3 -3
- package/dist/tsup/{chunk-6TQSSJ4F.cjs.map → chunk-MALSPBAF.cjs.map} +1 -1
- package/dist/tsup/{chunk-UZXQEGVJ.js → chunk-MMMEZM5J.js} +4 -4
- package/dist/tsup/chunk-MMMEZM5J.js.map +1 -0
- package/dist/tsup/{chunk-63WNTDRC.cjs → chunk-QAZLM4WT.cjs} +3 -3
- package/dist/tsup/{chunk-63WNTDRC.cjs.map → chunk-QAZLM4WT.cjs.map} +1 -1
- package/dist/tsup/{chunk-D5G75T7J.js → chunk-T6YVRM4K.js} +1 -3
- package/dist/tsup/chunk-T6YVRM4K.js.map +1 -0
- package/dist/tsup/{chunk-HGW6PBWR.cjs → chunk-VJFRBJVQ.cjs} +9 -137
- package/dist/tsup/chunk-VJFRBJVQ.cjs.map +1 -0
- package/dist/tsup/{chunk-GBG63SUG.js → chunk-VRCIXJRN.js} +5 -7
- package/dist/tsup/chunk-VRCIXJRN.js.map +1 -0
- package/dist/tsup/{chunk-KY3CERZR.js → chunk-W7EYSYVI.js} +4 -132
- package/dist/tsup/chunk-W7EYSYVI.js.map +1 -0
- package/dist/tsup/{chunk-SRNOPUC6.cjs → chunk-WQ4HNA4W.cjs} +2 -4
- package/dist/tsup/chunk-WQ4HNA4W.cjs.map +1 -0
- package/dist/tsup/{chunk-BATTOVHF.cjs → chunk-Y5NSCZA2.cjs} +12 -14
- package/dist/tsup/chunk-Y5NSCZA2.cjs.map +1 -0
- package/dist/tsup/client/mod.cjs +7 -7
- package/dist/tsup/client/mod.d.cts +2 -2
- package/dist/tsup/client/mod.d.ts +2 -2
- package/dist/tsup/client/mod.js +6 -6
- 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/{config-Ak1lv4gF.d.ts → config-0Ta55UV0.d.ts} +6 -27
- package/dist/tsup/{config-DU_xj4qZ.d.cts → config-Ca8dN4cS.d.cts} +6 -27
- package/dist/tsup/{context-DAAp4Lpg.d.ts → context-B_IWbWne.d.ts} +1 -1
- package/dist/tsup/{context-Dt_L55q8.d.cts → context-CUrQ9MHc.d.cts} +1 -1
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/mod.cjs +355 -482
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +3 -3
- package/dist/tsup/mod.d.ts +3 -3
- package/dist/tsup/mod.js +276 -403
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +10 -10
- package/dist/tsup/test/mod.d.cts +1 -1
- package/dist/tsup/test/mod.d.ts +1 -1
- package/dist/tsup/test/mod.js +6 -6
- package/dist/tsup/utils.cjs +3 -3
- package/dist/tsup/utils.js +2 -2
- package/dist/tsup/workflow/mod.cjs +16 -41
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +3 -3
- package/dist/tsup/workflow/mod.d.ts +3 -3
- package/dist/tsup/workflow/mod.js +10 -35
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +10 -11
- package/src/actor/config.ts +0 -3
- package/src/actor/errors.ts +2 -2
- package/src/agent-os/actor/session.ts +2 -2
- package/src/client/actor-conn.ts +34 -6
- package/src/client/actor-handle.ts +1 -2
- package/src/client/queue.ts +1 -2
- package/src/client/utils.ts +1 -0
- package/src/common/encoding.ts +5 -243
- package/src/common/inline-websocket-adapter.ts +12 -12
- package/src/common/log.ts +0 -1
- package/src/common/router.ts +2 -2
- package/src/common/utils.ts +148 -0
- package/src/drivers/engine/actor-driver.ts +11 -11
- package/src/engine-client/actor-websocket-client.ts +1 -2
- package/src/engine-client/mod.ts +2 -3
- package/src/registry/index.ts +109 -46
- package/src/registry/napi-runtime.ts +34 -11
- package/src/registry/native.ts +162 -205
- package/src/registry/runtime.ts +12 -5
- package/src/registry/wasm-runtime.ts +13 -2
- package/src/serde.ts +2 -2
- package/src/workflow/context.ts +5 -32
- package/src/workflow/inspector.ts +1 -2
- package/dist/tsup/chunk-7HLFSAJP.cjs.map +0 -1
- package/dist/tsup/chunk-AWTPTUQ7.cjs.map +0 -1
- package/dist/tsup/chunk-BATTOVHF.cjs.map +0 -1
- package/dist/tsup/chunk-D5G75T7J.js.map +0 -1
- package/dist/tsup/chunk-EMFKMVJR.js.map +0 -1
- package/dist/tsup/chunk-GBG63SUG.js.map +0 -1
- package/dist/tsup/chunk-HGW6PBWR.cjs.map +0 -1
- package/dist/tsup/chunk-KY3CERZR.js.map +0 -1
- package/dist/tsup/chunk-SRNOPUC6.cjs.map +0 -1
- package/dist/tsup/chunk-TMLOKTRB.js.map +0 -1
- package/dist/tsup/chunk-UZXQEGVJ.js.map +0 -1
- package/dist/tsup/process-metrics-NW754INA.js +0 -118
- package/dist/tsup/process-metrics-NW754INA.js.map +0 -1
- package/dist/tsup/process-metrics-TYAGKCEJ.cjs +0 -118
- package/dist/tsup/process-metrics-TYAGKCEJ.cjs.map +0 -1
- package/src/registry/process-metrics.ts +0 -183
- package/src/registry/write-through-proxy.ts +0 -40
- /package/dist/tsup/{chunk-D3T3ZBSY.js.map → chunk-H37XQU3I.js.map} +0 -0
- /package/dist/tsup/{chunk-4JU3IPG2.js.map → chunk-H7P7WR2Y.js.map} +0 -0
- /package/dist/tsup/{chunk-VUGENVIK.js.map → chunk-KJTA3ATT.js.map} +0 -0
package/src/registry/native.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { VirtualWebSocket } from "@rivetkit/virtual-websocket";
|
|
|
2
2
|
import {
|
|
3
3
|
ACTOR_CONTEXT_INTERNAL_SYMBOL,
|
|
4
4
|
CONN_STATE_MANAGER_SYMBOL,
|
|
5
|
-
RAW_STATE_SYMBOL,
|
|
6
5
|
getRunFunction,
|
|
7
6
|
getRunInspectorConfig,
|
|
8
7
|
type WorkflowInspectorConfig,
|
|
@@ -34,10 +33,6 @@ import { HEADER_CONN_PARAMS } from "@/common/actor-router-consts";
|
|
|
34
33
|
import type { AnyDatabaseProvider } from "@/common/database/config";
|
|
35
34
|
import { wrapJsNativeDatabase } from "@/common/database/native-database";
|
|
36
35
|
import { decodeWorkflowHistoryTransport } from "@/common/inspector-transport";
|
|
37
|
-
import {
|
|
38
|
-
assertJsonCompatValue,
|
|
39
|
-
type JsonCompatValue,
|
|
40
|
-
} from "@/common/encoding";
|
|
41
36
|
import { deconstructError, stringifyError } from "@/common/utils";
|
|
42
37
|
import type {
|
|
43
38
|
RivetCloseEvent,
|
|
@@ -59,7 +54,6 @@ import {
|
|
|
59
54
|
} from "@/serde";
|
|
60
55
|
import { getEnvUniversal, VERSION } from "@/utils";
|
|
61
56
|
import { logger } from "./log";
|
|
62
|
-
import { createWriteThroughProxy } from "./write-through-proxy";
|
|
63
57
|
import { loadNapiRuntime } from "./napi-runtime";
|
|
64
58
|
import {
|
|
65
59
|
type NativeValidationConfig,
|
|
@@ -249,6 +243,14 @@ type NativePersistActorState = {
|
|
|
249
243
|
state: unknown;
|
|
250
244
|
isInOnStateChange: boolean;
|
|
251
245
|
connStates: Map<string, NativePersistConnState>;
|
|
246
|
+
// Memoized deep write-through proxy and the state object it wraps. Rebuilt
|
|
247
|
+
// only when the underlying state object identity changes.
|
|
248
|
+
stateProxy?: unknown;
|
|
249
|
+
stateProxyTarget?: unknown;
|
|
250
|
+
// Set when a coalesced save and onStateChange flush is pending for the
|
|
251
|
+
// current event loop tick.
|
|
252
|
+
saveScheduled?: boolean;
|
|
253
|
+
pendingSaveHandle?: ReturnType<typeof setImmediate>;
|
|
252
254
|
};
|
|
253
255
|
type NativeDestroyGate = {
|
|
254
256
|
destroyCompletion?: Promise<void>;
|
|
@@ -343,15 +345,6 @@ function databaseNotConfiguredError(): RivetError {
|
|
|
343
345
|
);
|
|
344
346
|
}
|
|
345
347
|
|
|
346
|
-
function databaseClientNotReadyError(): RivetError {
|
|
347
|
-
return new RivetError(
|
|
348
|
-
"actor",
|
|
349
|
-
"database_client_not_ready",
|
|
350
|
-
"actor database client was not initialized before user code ran. this is an internal lifecycle error; the migration callback should have pre-warmed the client. file an issue if you can reproduce.",
|
|
351
|
-
{ public: true },
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
348
|
function stateNotEnabledError(): RivetError {
|
|
356
349
|
return new RivetError(
|
|
357
350
|
"actor",
|
|
@@ -421,20 +414,7 @@ async function cleanupNativeSleepRuntimeState(
|
|
|
421
414
|
runtime: CoreRuntime,
|
|
422
415
|
ctx: ActorContextHandle,
|
|
423
416
|
): Promise<void> {
|
|
424
|
-
|
|
425
|
-
const drained = await runtime.actorWaitForTrackedShutdownWork(ctx);
|
|
426
|
-
const waitMs = Date.now() - waitStarted;
|
|
427
|
-
if (drained) {
|
|
428
|
-
logger().debug({
|
|
429
|
-
msg: "sleep cleanup: tracked shutdown work drained",
|
|
430
|
-
waitMs,
|
|
431
|
-
});
|
|
432
|
-
} else {
|
|
433
|
-
logger().warn({
|
|
434
|
-
msg: "sleep cleanup: shutdown deadline reached before tracked work drained; closing DB anyway",
|
|
435
|
-
waitMs,
|
|
436
|
-
});
|
|
437
|
-
}
|
|
417
|
+
await runtime.actorWaitForTrackedShutdownWork(ctx);
|
|
438
418
|
await closeNativeDatabaseClient(runtime, ctx);
|
|
439
419
|
await closeNativeSqlDatabase(runtime, ctx);
|
|
440
420
|
clearNativeRuntimeState(runtime, ctx);
|
|
@@ -611,7 +591,7 @@ function decodeValue<T>(value?: RuntimeBytes | null): T {
|
|
|
611
591
|
}
|
|
612
592
|
|
|
613
593
|
function encodeValue(value: unknown): RuntimeBytes {
|
|
614
|
-
return encodeCborCompat(value
|
|
594
|
+
return encodeCborCompat(value);
|
|
615
595
|
}
|
|
616
596
|
|
|
617
597
|
function unwrapTsfnPayload<T>(error: unknown, payload: T): T {
|
|
@@ -1086,6 +1066,54 @@ function decodeArgs(value?: RuntimeBytes | null): unknown[] {
|
|
|
1086
1066
|
: [decoded];
|
|
1087
1067
|
}
|
|
1088
1068
|
|
|
1069
|
+
function createWriteThroughProxy<T>(
|
|
1070
|
+
value: T,
|
|
1071
|
+
commit: (next: T) => void,
|
|
1072
|
+
beforeChange?: () => void,
|
|
1073
|
+
): T {
|
|
1074
|
+
if (!value || typeof value !== "object") {
|
|
1075
|
+
return value;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
const proxies = new WeakMap<object, object>();
|
|
1079
|
+
const wrap = (target: object): object => {
|
|
1080
|
+
const cached = proxies.get(target);
|
|
1081
|
+
if (cached) {
|
|
1082
|
+
return cached;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
const proxy = new Proxy(target, {
|
|
1086
|
+
get(innerTarget, property, receiver) {
|
|
1087
|
+
const result = Reflect.get(innerTarget, property, receiver);
|
|
1088
|
+
return result && typeof result === "object"
|
|
1089
|
+
? wrap(result as object)
|
|
1090
|
+
: result;
|
|
1091
|
+
},
|
|
1092
|
+
set(innerTarget, property, nextValue, receiver) {
|
|
1093
|
+
beforeChange?.();
|
|
1094
|
+
const updated = Reflect.set(
|
|
1095
|
+
innerTarget,
|
|
1096
|
+
property,
|
|
1097
|
+
nextValue,
|
|
1098
|
+
receiver,
|
|
1099
|
+
);
|
|
1100
|
+
commit(value);
|
|
1101
|
+
return updated;
|
|
1102
|
+
},
|
|
1103
|
+
deleteProperty(innerTarget, property) {
|
|
1104
|
+
beforeChange?.();
|
|
1105
|
+
const updated = Reflect.deleteProperty(innerTarget, property);
|
|
1106
|
+
commit(value);
|
|
1107
|
+
return updated;
|
|
1108
|
+
},
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
proxies.set(target, proxy);
|
|
1112
|
+
return proxy;
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
return wrap(value as object) as T;
|
|
1116
|
+
}
|
|
1089
1117
|
|
|
1090
1118
|
function buildRequest(init: {
|
|
1091
1119
|
method: string;
|
|
@@ -1176,21 +1204,14 @@ class NativeConnAdapter {
|
|
|
1176
1204
|
);
|
|
1177
1205
|
}
|
|
1178
1206
|
|
|
1179
|
-
[RAW_STATE_SYMBOL](): unknown {
|
|
1180
|
-
return this.#readState();
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
1207
|
get state(): unknown {
|
|
1184
1208
|
const nextState = this.#readState();
|
|
1185
1209
|
return createWriteThroughProxy(nextState, (nextValue) => {
|
|
1186
1210
|
this.#writeState(nextValue, { writeNative: true });
|
|
1187
|
-
}, (newValue) => {
|
|
1188
|
-
assertJsonCompatValue(newValue);
|
|
1189
1211
|
});
|
|
1190
1212
|
}
|
|
1191
1213
|
|
|
1192
1214
|
set state(value: unknown) {
|
|
1193
|
-
assertJsonCompatValue(value);
|
|
1194
1215
|
this.#writeState(value, { writeNative: true });
|
|
1195
1216
|
}
|
|
1196
1217
|
|
|
@@ -2302,90 +2323,6 @@ class TrackedWebSocketHandleAdapter implements UniversalWebSocket {
|
|
|
2302
2323
|
}
|
|
2303
2324
|
}
|
|
2304
2325
|
|
|
2305
|
-
class NativeConnectionMap implements ReadonlyMap<string, NativeConnAdapter> {
|
|
2306
|
-
#runtime: CoreRuntime;
|
|
2307
|
-
#ctx: ActorContextHandle;
|
|
2308
|
-
#schemas: NativeValidationConfig;
|
|
2309
|
-
|
|
2310
|
-
constructor(
|
|
2311
|
-
runtime: CoreRuntime,
|
|
2312
|
-
ctx: ActorContextHandle,
|
|
2313
|
-
schemas: NativeValidationConfig,
|
|
2314
|
-
) {
|
|
2315
|
-
this.#runtime = runtime;
|
|
2316
|
-
this.#ctx = ctx;
|
|
2317
|
-
this.#schemas = schemas;
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
#connToAdapter(conn: ConnHandle): NativeConnAdapter {
|
|
2321
|
-
return new NativeConnAdapter(
|
|
2322
|
-
this.#runtime,
|
|
2323
|
-
conn,
|
|
2324
|
-
this.#schemas,
|
|
2325
|
-
this.#ctx,
|
|
2326
|
-
(connId) =>
|
|
2327
|
-
callNativeSync(() =>
|
|
2328
|
-
this.#runtime.actorQueueHibernationRemoval(
|
|
2329
|
-
this.#ctx,
|
|
2330
|
-
connId,
|
|
2331
|
-
),
|
|
2332
|
-
),
|
|
2333
|
-
);
|
|
2334
|
-
}
|
|
2335
|
-
|
|
2336
|
-
get size(): number {
|
|
2337
|
-
return callNativeSync(() => this.#runtime.actorConns(this.#ctx)).length;
|
|
2338
|
-
}
|
|
2339
|
-
|
|
2340
|
-
get(key: string): NativeConnAdapter | undefined {
|
|
2341
|
-
const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
|
|
2342
|
-
const conn = conns.find(
|
|
2343
|
-
(c) => this.#runtime.connId(c) === key,
|
|
2344
|
-
);
|
|
2345
|
-
if (!conn) return undefined;
|
|
2346
|
-
return this.#connToAdapter(conn);
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
has(key: string): boolean {
|
|
2350
|
-
const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
|
|
2351
|
-
return conns.some((c) => this.#runtime.connId(c) === key);
|
|
2352
|
-
}
|
|
2353
|
-
|
|
2354
|
-
keys(): MapIterator<string> {
|
|
2355
|
-
const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
|
|
2356
|
-
return conns.map((c) => this.#runtime.connId(c))[Symbol.iterator]() satisfies MapIterator<string>;
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
|
-
values(): MapIterator<NativeConnAdapter> {
|
|
2360
|
-
const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
|
|
2361
|
-
return conns.map((c) => this.#connToAdapter(c))[Symbol.iterator]() satisfies MapIterator<NativeConnAdapter>;
|
|
2362
|
-
}
|
|
2363
|
-
|
|
2364
|
-
entries(): MapIterator<[string, NativeConnAdapter]> {
|
|
2365
|
-
const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
|
|
2366
|
-
return conns.map(
|
|
2367
|
-
(c) => [this.#runtime.connId(c), this.#connToAdapter(c)] as [string, NativeConnAdapter],
|
|
2368
|
-
)[Symbol.iterator]() satisfies MapIterator<[string, NativeConnAdapter]>;
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
forEach(
|
|
2372
|
-
callback: (value: NativeConnAdapter, key: string, map: ReadonlyMap<string, NativeConnAdapter>) => void,
|
|
2373
|
-
thisArg?: unknown,
|
|
2374
|
-
): void {
|
|
2375
|
-
const conns = callNativeSync(() => this.#runtime.actorConns(this.#ctx));
|
|
2376
|
-
for (const conn of conns) {
|
|
2377
|
-
const id = this.#runtime.connId(conn);
|
|
2378
|
-
callback.call(thisArg, this.#connToAdapter(conn), id, this);
|
|
2379
|
-
}
|
|
2380
|
-
}
|
|
2381
|
-
|
|
2382
|
-
[Symbol.iterator](): MapIterator<[string, NativeConnAdapter]> {
|
|
2383
|
-
return this.entries();
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
|
-
readonly [Symbol.toStringTag] = "NativeConnectionMap";
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2389
2326
|
export class ActorContextHandleAdapter {
|
|
2390
2327
|
#runtime: CoreRuntime;
|
|
2391
2328
|
#ctx: ActorContextHandle;
|
|
@@ -2394,9 +2331,9 @@ export class ActorContextHandleAdapter {
|
|
|
2394
2331
|
#abortSignalCleanup?: () => void;
|
|
2395
2332
|
#client?: AnyClient;
|
|
2396
2333
|
#clientFactory?: () => AnyClient;
|
|
2397
|
-
#connMap?: NativeConnectionMap;
|
|
2398
2334
|
#databaseProvider?: Exclude<AnyDatabaseProvider, undefined>;
|
|
2399
2335
|
#db?: unknown;
|
|
2336
|
+
#dbProxy?: unknown;
|
|
2400
2337
|
#dispatchCancelToken?: CancellationTokenHandle;
|
|
2401
2338
|
#kv?: NativeKvAdapter;
|
|
2402
2339
|
#queue?: NativeQueueAdapter;
|
|
@@ -2459,42 +2396,60 @@ export class ActorContextHandleAdapter {
|
|
|
2459
2396
|
throw databaseNotConfiguredError();
|
|
2460
2397
|
}
|
|
2461
2398
|
|
|
2462
|
-
if (this.#
|
|
2463
|
-
|
|
2464
|
-
|
|
2399
|
+
if (!this.#dbProxy) {
|
|
2400
|
+
this.#dbProxy = new Proxy(
|
|
2401
|
+
{},
|
|
2402
|
+
{
|
|
2403
|
+
get: (_target, property) => {
|
|
2404
|
+
if (property === "then") {
|
|
2405
|
+
return undefined;
|
|
2406
|
+
}
|
|
2465
2407
|
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2408
|
+
return async (...args: Array<unknown>) => {
|
|
2409
|
+
const client = await this.ensureDatabaseClient();
|
|
2410
|
+
const value = Reflect.get(
|
|
2411
|
+
client as object,
|
|
2412
|
+
property,
|
|
2413
|
+
);
|
|
2414
|
+
if (typeof value !== "function") {
|
|
2415
|
+
return value;
|
|
2416
|
+
}
|
|
2417
|
+
return await value.apply(client, args);
|
|
2418
|
+
};
|
|
2419
|
+
},
|
|
2420
|
+
},
|
|
2421
|
+
);
|
|
2471
2422
|
}
|
|
2472
2423
|
|
|
2473
|
-
|
|
2474
|
-
}
|
|
2475
|
-
|
|
2476
|
-
[RAW_STATE_SYMBOL](): unknown {
|
|
2477
|
-
if (!this.#stateEnabled) {
|
|
2478
|
-
throw stateNotEnabledError();
|
|
2479
|
-
}
|
|
2480
|
-
return this.#readState();
|
|
2424
|
+
return this.#dbProxy;
|
|
2481
2425
|
}
|
|
2482
2426
|
|
|
2483
2427
|
get state(): unknown {
|
|
2484
2428
|
if (!this.#stateEnabled) {
|
|
2485
2429
|
throw stateNotEnabledError();
|
|
2486
2430
|
}
|
|
2431
|
+
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
2487
2432
|
const nextState = this.#readState();
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2433
|
+
// Reading `c.state` rebuilds the deep write-through proxy, which
|
|
2434
|
+
// allocates fresh on-change caches and rewraps the whole tree. Memoize
|
|
2435
|
+
// the proxy keyed on the underlying state object so repeated reads and
|
|
2436
|
+
// deep read cascades reuse a single proxy.
|
|
2437
|
+
if (
|
|
2438
|
+
actorState.stateProxy === undefined ||
|
|
2439
|
+
actorState.stateProxyTarget !== nextState
|
|
2440
|
+
) {
|
|
2441
|
+
actorState.stateProxyTarget = nextState;
|
|
2442
|
+
actorState.stateProxy = createWriteThroughProxy(
|
|
2443
|
+
nextState,
|
|
2444
|
+
(nextValue) => {
|
|
2445
|
+
this.#writeState(nextValue, { scheduleSave: true });
|
|
2446
|
+
},
|
|
2447
|
+
() => {
|
|
2448
|
+
this.#assertCanMutateState();
|
|
2449
|
+
},
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
return actorState.stateProxy;
|
|
2498
2453
|
}
|
|
2499
2454
|
|
|
2500
2455
|
set state(value: unknown) {
|
|
@@ -2502,7 +2457,6 @@ export class ActorContextHandleAdapter {
|
|
|
2502
2457
|
throw stateNotEnabledError();
|
|
2503
2458
|
}
|
|
2504
2459
|
this.#assertCanMutateState();
|
|
2505
|
-
assertJsonCompatValue(value);
|
|
2506
2460
|
this.#writeState(value, { scheduleSave: true });
|
|
2507
2461
|
}
|
|
2508
2462
|
|
|
@@ -2569,11 +2523,27 @@ export class ActorContextHandleAdapter {
|
|
|
2569
2523
|
return callNativeSync(() => this.#runtime.actorRegion(this.#ctx));
|
|
2570
2524
|
}
|
|
2571
2525
|
|
|
2572
|
-
get conns():
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2526
|
+
get conns(): Map<string, NativeConnAdapter> {
|
|
2527
|
+
return new Map(
|
|
2528
|
+
callNativeSync(() => this.#runtime.actorConns(this.#ctx)).map(
|
|
2529
|
+
(conn) => [
|
|
2530
|
+
this.#runtime.connId(conn),
|
|
2531
|
+
new NativeConnAdapter(
|
|
2532
|
+
this.#runtime,
|
|
2533
|
+
conn,
|
|
2534
|
+
this.#schemas,
|
|
2535
|
+
this.#ctx,
|
|
2536
|
+
(connId) =>
|
|
2537
|
+
callNativeSync(() =>
|
|
2538
|
+
this.#runtime.actorQueueHibernationRemoval(
|
|
2539
|
+
this.#ctx,
|
|
2540
|
+
connId,
|
|
2541
|
+
),
|
|
2542
|
+
),
|
|
2543
|
+
),
|
|
2544
|
+
],
|
|
2545
|
+
),
|
|
2546
|
+
);
|
|
2577
2547
|
}
|
|
2578
2548
|
|
|
2579
2549
|
get log() {
|
|
@@ -2804,41 +2774,22 @@ export class ActorContextHandleAdapter {
|
|
|
2804
2774
|
}
|
|
2805
2775
|
|
|
2806
2776
|
keepAwake<T>(promise: Promise<T>): Promise<T> {
|
|
2807
|
-
const startedAt = Date.now();
|
|
2808
|
-
logger().debug({
|
|
2809
|
-
msg: "keepAwake registered",
|
|
2810
|
-
at: startedAt,
|
|
2811
|
-
});
|
|
2812
2777
|
const trackedPromise = Promise.resolve(promise)
|
|
2813
|
-
.
|
|
2814
|
-
()
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
},
|
|
2820
|
-
(error) => {
|
|
2821
|
-
logger().warn({
|
|
2822
|
-
msg: "keepAwake promise rejected",
|
|
2823
|
-
durationMs: Date.now() - startedAt,
|
|
2824
|
-
error: stringifyError(error),
|
|
2825
|
-
});
|
|
2826
|
-
},
|
|
2827
|
-
)
|
|
2778
|
+
.catch((error) => {
|
|
2779
|
+
logger().warn({
|
|
2780
|
+
msg: "keepAwake promise rejected",
|
|
2781
|
+
error: stringifyError(error),
|
|
2782
|
+
});
|
|
2783
|
+
})
|
|
2828
2784
|
.then(() => null);
|
|
2829
2785
|
try {
|
|
2830
2786
|
callNativeSync(() =>
|
|
2831
2787
|
this.#runtime.actorKeepAwake(this.#ctx, trackedPromise),
|
|
2832
2788
|
);
|
|
2833
2789
|
} catch (error) {
|
|
2834
|
-
if (isClosedTaskRegistrationError(error)) {
|
|
2835
|
-
|
|
2836
|
-
msg: "keepAwake registration dropped (teardown already started); promise will not delay grace",
|
|
2837
|
-
error: stringifyError(error),
|
|
2838
|
-
});
|
|
2839
|
-
return promise;
|
|
2790
|
+
if (!isClosedTaskRegistrationError(error)) {
|
|
2791
|
+
throw error;
|
|
2840
2792
|
}
|
|
2841
|
-
throw error;
|
|
2842
2793
|
}
|
|
2843
2794
|
return promise;
|
|
2844
2795
|
}
|
|
@@ -2934,6 +2885,9 @@ export class ActorContextHandleAdapter {
|
|
|
2934
2885
|
}
|
|
2935
2886
|
|
|
2936
2887
|
async dispose(): Promise<void> {
|
|
2888
|
+
// Flush any save coalesced for this tick before the context is torn
|
|
2889
|
+
// down so the request-save and onStateChange always run.
|
|
2890
|
+
this.#flushStateChange();
|
|
2937
2891
|
this.#abortSignalCleanup?.();
|
|
2938
2892
|
this.#sql = undefined;
|
|
2939
2893
|
}
|
|
@@ -2969,13 +2923,12 @@ export class ActorContextHandleAdapter {
|
|
|
2969
2923
|
scheduleSave: boolean;
|
|
2970
2924
|
},
|
|
2971
2925
|
): void {
|
|
2972
|
-
encodeValue(value);
|
|
2973
2926
|
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
2974
2927
|
actorState.state = value;
|
|
2975
2928
|
if (!options.scheduleSave) {
|
|
2976
2929
|
return;
|
|
2977
2930
|
}
|
|
2978
|
-
this.#
|
|
2931
|
+
this.#scheduleSave();
|
|
2979
2932
|
}
|
|
2980
2933
|
|
|
2981
2934
|
#assertCanMutateState(): void {
|
|
@@ -2985,9 +2938,33 @@ export class ActorContextHandleAdapter {
|
|
|
2985
2938
|
}
|
|
2986
2939
|
}
|
|
2987
2940
|
|
|
2988
|
-
|
|
2941
|
+
// Coalesce the request-save and onStateChange work to once per event loop
|
|
2942
|
+
// tick. A synchronous burst of mutations (for example
|
|
2943
|
+
// `Object.assign(c.state, ...)`) would otherwise cross the NAPI boundary and
|
|
2944
|
+
// run onStateChange once per field, re-serializing the whole state each time
|
|
2945
|
+
// and pinning the event loop on large state.
|
|
2946
|
+
#scheduleSave(): void {
|
|
2947
|
+
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
2948
|
+
if (actorState.saveScheduled) {
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
actorState.saveScheduled = true;
|
|
2952
|
+
actorState.pendingSaveHandle = setImmediate(() => {
|
|
2953
|
+
this.#flushStateChange();
|
|
2954
|
+
});
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
#flushStateChange(): void {
|
|
2989
2958
|
const actorState = getNativePersistState(this.#runtime, this.#ctx);
|
|
2990
|
-
|
|
2959
|
+
if (!actorState.saveScheduled) {
|
|
2960
|
+
return;
|
|
2961
|
+
}
|
|
2962
|
+
actorState.saveScheduled = false;
|
|
2963
|
+
if (actorState.pendingSaveHandle !== undefined) {
|
|
2964
|
+
clearImmediate(actorState.pendingSaveHandle);
|
|
2965
|
+
actorState.pendingSaveHandle = undefined;
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2991
2968
|
callNativeSync(() =>
|
|
2992
2969
|
this.#runtime.actorRequestSave(this.#ctx, { immediate: false }),
|
|
2993
2970
|
);
|
|
@@ -3571,10 +3548,6 @@ export function buildNativeFactory(
|
|
|
3571
3548
|
getNativeWorkflowInspector(ctx) !== undefined,
|
|
3572
3549
|
});
|
|
3573
3550
|
} catch (error) {
|
|
3574
|
-
logger().error({
|
|
3575
|
-
msg: "error replaying workflow history",
|
|
3576
|
-
error,
|
|
3577
|
-
});
|
|
3578
3551
|
return errorResponse(error);
|
|
3579
3552
|
}
|
|
3580
3553
|
}
|
|
@@ -3754,10 +3727,6 @@ export function buildNativeFactory(
|
|
|
3754
3727
|
);
|
|
3755
3728
|
return jsonResponse({ output });
|
|
3756
3729
|
} catch (error) {
|
|
3757
|
-
logger().error({
|
|
3758
|
-
msg: "Error handling inspector action request",
|
|
3759
|
-
error,
|
|
3760
|
-
});
|
|
3761
3730
|
return errorResponse(error);
|
|
3762
3731
|
}
|
|
3763
3732
|
}
|
|
@@ -3772,10 +3741,6 @@ export function buildNativeFactory(
|
|
|
3772
3741
|
{ status: 404 },
|
|
3773
3742
|
);
|
|
3774
3743
|
} catch (error) {
|
|
3775
|
-
logger().error({
|
|
3776
|
-
msg: "Error handling inspector request",
|
|
3777
|
-
error,
|
|
3778
|
-
});
|
|
3779
3744
|
return errorResponse(error);
|
|
3780
3745
|
} finally {
|
|
3781
3746
|
await actorCtx.dispose();
|
|
@@ -4686,14 +4651,6 @@ export async function buildConfiguredRegistry(config: RegistryConfig): Promise<{
|
|
|
4686
4651
|
serveConfig: RuntimeServeConfig;
|
|
4687
4652
|
}> {
|
|
4688
4653
|
const runtime = await loadConfiguredRuntime(config);
|
|
4689
|
-
if (runtime.kind === "napi") {
|
|
4690
|
-
// Start Node.js runtime health metrics collection (event loop lag,
|
|
4691
|
-
// GC, heap, CPU, libuv handles). Only available on the native NAPI
|
|
4692
|
-
// runtime; wasm/edge hosts do not expose perf_hooks/v8 the same
|
|
4693
|
-
// way and have no Rust-side prometheus collectors loaded.
|
|
4694
|
-
const { startProcessMetrics } = await import("./process-metrics");
|
|
4695
|
-
startProcessMetrics();
|
|
4696
|
-
}
|
|
4697
4654
|
return buildRegistryWithRuntime(
|
|
4698
4655
|
normalizeRuntimeConfig(config, runtime),
|
|
4699
4656
|
runtime,
|
package/src/registry/runtime.ts
CHANGED
|
@@ -257,9 +257,10 @@ export interface RuntimeServerlessResponseHead {
|
|
|
257
257
|
headers: Record<string, string>;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
export interface
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
export interface RuntimeRegistryRouteResponse {
|
|
261
|
+
status: number;
|
|
262
|
+
headers: Record<string, string>;
|
|
263
|
+
body: RuntimeBytes;
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
export type RuntimeServerlessStreamEvent =
|
|
@@ -319,9 +320,15 @@ export interface CoreRuntime {
|
|
|
319
320
|
cancelToken: CancellationTokenHandle,
|
|
320
321
|
config: RuntimeServeConfig,
|
|
321
322
|
): Promise<RuntimeServerlessResponseHead>;
|
|
322
|
-
|
|
323
|
+
registryHealth?(
|
|
324
|
+
registry: RegistryHandle,
|
|
325
|
+
): Promise<RuntimeRegistryRouteResponse>;
|
|
326
|
+
registryMetadata?(
|
|
327
|
+
registry: RegistryHandle,
|
|
328
|
+
): Promise<RuntimeRegistryRouteResponse>;
|
|
329
|
+
registryMetrics?(
|
|
323
330
|
registry: RegistryHandle,
|
|
324
|
-
): Promise<
|
|
331
|
+
): Promise<RuntimeRegistryRouteResponse>;
|
|
325
332
|
createActorFactory(
|
|
326
333
|
callbacks: object,
|
|
327
334
|
config?: RuntimeActorConfig | undefined | null,
|
|
@@ -33,6 +33,7 @@ import type {
|
|
|
33
33
|
RuntimeQueueTryNextBatchOptions,
|
|
34
34
|
RuntimeQueueWaitOptions,
|
|
35
35
|
RuntimeRequestSaveOpts,
|
|
36
|
+
RuntimeRegistryRouteResponse,
|
|
36
37
|
RuntimeServeConfig,
|
|
37
38
|
RuntimeServerlessRequest,
|
|
38
39
|
RuntimeServerlessResponseHead,
|
|
@@ -270,8 +271,18 @@ export class WasmCoreRuntime implements CoreRuntime {
|
|
|
270
271
|
await callWasm(() => asWasmRegistry(registry).shutdown());
|
|
271
272
|
}
|
|
272
273
|
|
|
273
|
-
async
|
|
274
|
-
return {
|
|
274
|
+
async registryHealth(): Promise<RuntimeRegistryRouteResponse> {
|
|
275
|
+
return {
|
|
276
|
+
status: 200,
|
|
277
|
+
headers: { "content-type": "application/json" },
|
|
278
|
+
body: new TextEncoder().encode(
|
|
279
|
+
JSON.stringify({
|
|
280
|
+
status: "ok",
|
|
281
|
+
runtime: "rivetkit",
|
|
282
|
+
version: "wasm",
|
|
283
|
+
}),
|
|
284
|
+
),
|
|
285
|
+
};
|
|
275
286
|
}
|
|
276
287
|
|
|
277
288
|
async handleServerlessRequest(
|
package/src/serde.ts
CHANGED
|
@@ -3,7 +3,7 @@ import invariant from "invariant";
|
|
|
3
3
|
import type { VersionedDataHandler } from "vbare";
|
|
4
4
|
import type { z } from "zod/v4";
|
|
5
5
|
import { assertUnreachable } from "@/common/utils";
|
|
6
|
-
import type {
|
|
6
|
+
import type { Encoding } from "@/common/encoding";
|
|
7
7
|
import {
|
|
8
8
|
encodeJsonCompatValue,
|
|
9
9
|
jsonParseCompat,
|
|
@@ -46,7 +46,7 @@ export function contentTypeForEncoding(encoding: Encoding): string {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export function encodeCborCompat(value:
|
|
49
|
+
export function encodeCborCompat(value: unknown): Uint8Array {
|
|
50
50
|
return cbor.encode(encodeJsonCompatValue(value));
|
|
51
51
|
}
|
|
52
52
|
|
package/src/workflow/context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import {
|
|
2
|
+
import type { RunContext } from "@/actor/config";
|
|
3
3
|
import type {
|
|
4
4
|
QueueFilterName,
|
|
5
5
|
QueueNextBatchOptions,
|
|
@@ -247,14 +247,14 @@ export class ActorWorkflowContext<
|
|
|
247
247
|
}
|
|
248
248
|
return await this.#wrapActive(() =>
|
|
249
249
|
this.#inner.step(nameOrConfig, () =>
|
|
250
|
-
this.#
|
|
250
|
+
this.#withActorAccess(run),
|
|
251
251
|
),
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
254
|
const stepConfig = nameOrConfig as StepConfig<T>;
|
|
255
255
|
const config: StepConfig<T> = {
|
|
256
256
|
...stepConfig,
|
|
257
|
-
run: () => this.#
|
|
257
|
+
run: () => this.#withActorAccess(stepConfig.run),
|
|
258
258
|
};
|
|
259
259
|
return await this.#wrapActive(() => this.#inner.step(config));
|
|
260
260
|
}
|
|
@@ -271,14 +271,14 @@ export class ActorWorkflowContext<
|
|
|
271
271
|
}
|
|
272
272
|
return await this.#wrapActive(() =>
|
|
273
273
|
this.#inner.tryStep(nameOrConfig, () =>
|
|
274
|
-
this.#
|
|
274
|
+
this.#withActorAccess(run),
|
|
275
275
|
),
|
|
276
276
|
);
|
|
277
277
|
}
|
|
278
278
|
const stepConfig = nameOrConfig as TryStepConfig<T>;
|
|
279
279
|
const config: TryStepConfig<T> = {
|
|
280
280
|
...stepConfig,
|
|
281
|
-
run: () => this.#
|
|
281
|
+
run: () => this.#withActorAccess(stepConfig.run),
|
|
282
282
|
};
|
|
283
283
|
return await this.#wrapActive(() => this.#inner.tryStep(config));
|
|
284
284
|
}
|
|
@@ -612,33 +612,6 @@ export class ActorWorkflowContext<
|
|
|
612
612
|
}
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
-
async #withActorAccessAndStateRollback<T>(
|
|
616
|
-
run: () => Promise<T>,
|
|
617
|
-
): Promise<T> {
|
|
618
|
-
let stateSnapshot: { state: TState } | null = null;
|
|
619
|
-
try {
|
|
620
|
-
stateSnapshot = { state: this.#runCtx[RAW_STATE_SYMBOL]() };
|
|
621
|
-
} catch (error) {
|
|
622
|
-
this.#runCtx.log.debug({
|
|
623
|
-
msg: "failed to get state, likely due to being stateless workflow",
|
|
624
|
-
error,
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
if (stateSnapshot) {
|
|
628
|
-
stateSnapshot.state = structuredClone(stateSnapshot.state);
|
|
629
|
-
}
|
|
630
|
-
const varsSnapshot = structuredClone(this.#runCtx.vars);
|
|
631
|
-
try {
|
|
632
|
-
return await this.#withActorAccess(run);
|
|
633
|
-
} catch (error) {
|
|
634
|
-
if (stateSnapshot) {
|
|
635
|
-
this.#runCtx.state = stateSnapshot.state;
|
|
636
|
-
}
|
|
637
|
-
this.#runCtx.vars = varsSnapshot;
|
|
638
|
-
throw error;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
|
|
642
615
|
#ensureActorAccess(feature: string): void {
|
|
643
616
|
if (!this.#allowActorAccess) {
|
|
644
617
|
this.#guardViolation = true;
|