rivetkit 2.3.30 → 3.0.0-preview.2
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 +58 -9
- package/dist/browser/client.js +193 -20
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.js +1 -2
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/{chunk-P2PHHJMH.cjs → chunk-25MUHNWE.cjs} +326 -166
- package/dist/tsup/chunk-25MUHNWE.cjs.map +1 -0
- package/dist/tsup/{chunk-5SN6GAYX.cjs → chunk-3SPYZMME.cjs} +3 -3
- package/dist/tsup/{chunk-5SN6GAYX.cjs.map → chunk-3SPYZMME.cjs.map} +1 -1
- package/dist/tsup/{chunk-4SNS3PYZ.js → chunk-3URL73AV.js} +2 -2
- package/dist/tsup/{chunk-EKAQ7HG2.js → chunk-442XBCAF.js} +3 -3
- package/dist/tsup/{chunk-CORYIKDC.js → chunk-5F7FWAJI.js} +10 -11
- package/dist/tsup/chunk-5F7FWAJI.js.map +1 -0
- package/dist/tsup/{chunk-I472KTIC.js → chunk-6IGGYL2C.js} +185 -25
- package/dist/tsup/chunk-6IGGYL2C.js.map +1 -0
- package/dist/tsup/{chunk-JI6GZ2C2.js → chunk-A2CF6PFH.js} +18 -1
- package/dist/tsup/chunk-A2CF6PFH.js.map +1 -0
- package/dist/tsup/{chunk-OUB7SGSA.js → chunk-ANNVZW6B.js} +2 -2
- package/dist/tsup/{chunk-ZIIQQHC3.cjs → chunk-BCG7PTBS.cjs} +4 -4
- package/dist/tsup/{chunk-ZIIQQHC3.cjs.map → chunk-BCG7PTBS.cjs.map} +1 -1
- package/dist/tsup/{chunk-OJFVABRH.cjs → chunk-CJ3MX5MI.cjs} +7 -7
- package/dist/tsup/{chunk-OJFVABRH.cjs.map → chunk-CJ3MX5MI.cjs.map} +1 -1
- package/dist/tsup/{chunk-GEUBEODU.cjs → chunk-EPPV7WB2.cjs} +3 -3
- package/dist/tsup/{chunk-GEUBEODU.cjs.map → chunk-EPPV7WB2.cjs.map} +1 -1
- package/dist/tsup/{chunk-MXV26ZBB.js → chunk-OLZ4KAFL.js} +4 -4
- package/dist/tsup/{chunk-5UUOECX2.cjs → chunk-QDRZMCX5.cjs} +10 -10
- package/dist/tsup/{chunk-5UUOECX2.cjs.map → chunk-QDRZMCX5.cjs.map} +1 -1
- package/dist/tsup/{chunk-MYWZCDML.cjs → chunk-RTWH3AX3.cjs} +19 -2
- package/dist/tsup/chunk-RTWH3AX3.cjs.map +1 -0
- package/dist/tsup/{chunk-H3SGQEHZ.js → chunk-WGKL7HMH.js} +2 -2
- package/dist/tsup/{chunk-6LOYTFPZ.js → chunk-WGQHG26S.js} +2 -2
- package/dist/tsup/{chunk-2BIRGEIU.cjs → chunk-XSOHGU4G.cjs} +10 -11
- package/dist/tsup/chunk-XSOHGU4G.cjs.map +1 -0
- package/dist/tsup/{chunk-ABPZG7QV.cjs → chunk-YZVVID47.cjs} +3 -3
- package/dist/tsup/{chunk-ABPZG7QV.cjs.map → chunk-YZVVID47.cjs.map} +1 -1
- package/dist/tsup/client/mod.cjs +6 -6
- package/dist/tsup/client/mod.d.cts +15 -3
- package/dist/tsup/client/mod.d.ts +15 -3
- package/dist/tsup/client/mod.js +5 -5
- package/dist/tsup/common/log.cjs +2 -2
- package/dist/tsup/common/log.js +1 -1
- package/dist/tsup/common/websocket.cjs +3 -3
- package/dist/tsup/common/websocket.js +2 -2
- package/dist/tsup/{config-osdJqQwX.d.cts → config-8NgsxIcT.d.cts} +43 -12
- package/dist/tsup/{config-ey2I2zz5.d.ts → config-B2wlj9wx.d.cts} +7 -1
- package/dist/tsup/{config-ey2I2zz5.d.cts → config-B2wlj9wx.d.ts} +7 -1
- package/dist/tsup/{config-Cv6pjCt-.d.ts → config-DJ3KW-fe.d.ts} +43 -12
- package/dist/tsup/{context-CoVbKBuk.d.ts → context-BL8kUGjq.d.ts} +2 -2
- package/dist/tsup/{context-DpjrM7n7.d.cts → context-_RoE_YHL.d.cts} +2 -2
- package/dist/tsup/db/drizzle.cjs +2 -2
- package/dist/tsup/db/drizzle.d.cts +1 -1
- package/dist/tsup/db/drizzle.d.ts +1 -1
- package/dist/tsup/db/drizzle.js +1 -1
- package/dist/tsup/db/mod.cjs +3 -3
- package/dist/tsup/db/mod.d.cts +2 -2
- package/dist/tsup/db/mod.d.ts +2 -2
- package/dist/tsup/db/mod.js +2 -2
- package/dist/tsup/dynamic/mod.d.cts +2 -2
- package/dist/tsup/dynamic/mod.d.ts +2 -2
- package/dist/tsup/inspector/mod.cjs +5 -5
- package/dist/tsup/inspector/mod.js +4 -4
- package/dist/tsup/inspector/workflow.cjs +4 -4
- package/dist/tsup/inspector/workflow.js +3 -3
- package/dist/tsup/inspector-tab/mod.d.cts +3 -3
- package/dist/tsup/inspector-tab/mod.d.ts +3 -3
- package/dist/tsup/mod.cjs +254 -166
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +4 -4
- package/dist/tsup/mod.d.ts +4 -4
- package/dist/tsup/mod.js +168 -80
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +7 -7
- package/dist/tsup/test/mod.d.cts +2 -2
- package/dist/tsup/test/mod.d.ts +2 -2
- package/dist/tsup/test/mod.js +5 -5
- package/dist/tsup/unstable/migrations.d.cts +1 -1
- package/dist/tsup/unstable/migrations.d.ts +1 -1
- package/dist/tsup/utils.cjs +2 -2
- package/dist/tsup/utils.js +1 -1
- package/dist/tsup/workflow/mod.cjs +17 -17
- package/dist/tsup/workflow/mod.d.cts +4 -4
- package/dist/tsup/workflow/mod.d.ts +4 -4
- package/dist/tsup/workflow/mod.js +5 -5
- package/package.json +9 -10
- package/src/actor/keys.ts +86 -0
- package/src/client/actor-conn.ts +92 -6
- package/src/client/actor-handle.ts +21 -3
- package/src/client/client.ts +6 -0
- package/src/client/config.ts +12 -1
- package/src/client/lifecycle-errors.ts +16 -1
- package/src/client/retry-budget.ts +78 -0
- package/src/client/utils.ts +13 -2
- package/src/common/database/config.ts +7 -1
- package/src/common/database/native-database.ts +17 -6
- package/src/common/router.ts +1 -1
- package/src/engine-api/actors.ts +3 -3
- package/src/engine-client/actor-websocket-client.ts +4 -2
- package/src/engine-client/api-endpoints.ts +44 -14
- package/src/engine-client/mod.ts +2 -2
- package/src/registry/config/envoy.ts +1 -1
- package/src/registry/config/index.ts +28 -31
- package/src/registry/index.ts +51 -19
- package/src/registry/napi-runtime.ts +3 -2
- package/src/registry/native.ts +126 -34
- package/src/registry/runtime.ts +27 -10
- package/src/registry/wasm-runtime.ts +6 -3
- package/src/utils/env-vars.ts +15 -10
- package/dist/tsup/chunk-2BIRGEIU.cjs.map +0 -1
- package/dist/tsup/chunk-CORYIKDC.js.map +0 -1
- package/dist/tsup/chunk-I472KTIC.js.map +0 -1
- package/dist/tsup/chunk-JI6GZ2C2.js.map +0 -1
- package/dist/tsup/chunk-MYWZCDML.cjs.map +0 -1
- package/dist/tsup/chunk-P2PHHJMH.cjs.map +0 -1
- package/src/actor/config.test.ts +0 -78
- package/src/actor/keys.test.ts +0 -275
- package/src/actor/utils.test.ts +0 -48
- package/src/client/test.ts +0 -44
- package/src/client/token-provider.test.ts +0 -86
- package/src/common/database/mod.test.ts +0 -364
- package/src/common/database/native-database.test.ts +0 -220
- package/src/common/inline-websocket-adapter.test.ts +0 -51
- package/src/db/drizzle.test.ts +0 -164
- package/src/registry/config/index.test.ts +0 -25
- package/src/registry/run-handler-coordinator.test.ts +0 -252
- package/src/registry/runtime.test.ts +0 -124
- package/src/unstable/migrations.test.ts +0 -170
- package/src/utils/endpoint-parser.test.ts +0 -206
- package/src/utils.test.ts +0 -34
- package/src/workflow/driver.test.ts +0 -62
- /package/dist/tsup/{chunk-4SNS3PYZ.js.map → chunk-3URL73AV.js.map} +0 -0
- /package/dist/tsup/{chunk-EKAQ7HG2.js.map → chunk-442XBCAF.js.map} +0 -0
- /package/dist/tsup/{chunk-OUB7SGSA.js.map → chunk-ANNVZW6B.js.map} +0 -0
- /package/dist/tsup/{chunk-MXV26ZBB.js.map → chunk-OLZ4KAFL.js.map} +0 -0
- /package/dist/tsup/{chunk-H3SGQEHZ.js.map → chunk-WGKL7HMH.js.map} +0 -0
- /package/dist/tsup/{chunk-6LOYTFPZ.js.map → chunk-WGQHG26S.js.map} +0 -0
|
@@ -158,7 +158,7 @@ export const RegistryConfigSchema = z
|
|
|
158
158
|
// // created or must be imported async using `await import(...)`
|
|
159
159
|
// getUpgradeWebSocket: z.custom<GetUpgradeWebSocket>().optional(),
|
|
160
160
|
|
|
161
|
-
// MARK:
|
|
161
|
+
// MARK: Node Configuration
|
|
162
162
|
/**
|
|
163
163
|
* Endpoint to connect to for Rivet Engine.
|
|
164
164
|
*
|
|
@@ -251,14 +251,14 @@ export const RegistryConfigSchema = z
|
|
|
251
251
|
.default(() => getRivetRunEngineVersion() ?? VERSION),
|
|
252
252
|
/**
|
|
253
253
|
* Starts the first-party Services actor host when RivetKit manages
|
|
254
|
-
* a local engine.
|
|
255
|
-
*
|
|
254
|
+
* a local engine. Disabled by default. Set RIVET_RUN_SERVICES=1
|
|
255
|
+
* or startServices: true to enable it.
|
|
256
256
|
*/
|
|
257
257
|
startServices: z.boolean().optional(),
|
|
258
258
|
/**
|
|
259
259
|
* @experimental
|
|
260
260
|
*
|
|
261
|
-
* Automatically configure serverless
|
|
261
|
+
* Automatically configure serverless nodes in the engine.
|
|
262
262
|
*/
|
|
263
263
|
configurePool: ConfigurePoolSchema.optional(),
|
|
264
264
|
|
|
@@ -266,7 +266,7 @@ export const RegistryConfigSchema = z
|
|
|
266
266
|
serverless: ServerlessConfigSchema.optional().default(() =>
|
|
267
267
|
ServerlessConfigSchema.parse({}),
|
|
268
268
|
),
|
|
269
|
-
|
|
269
|
+
node: EnvoyConfigSchema.optional().default(() =>
|
|
270
270
|
EnvoyConfigSchema.parse({}),
|
|
271
271
|
),
|
|
272
272
|
|
|
@@ -274,9 +274,9 @@ export const RegistryConfigSchema = z
|
|
|
274
274
|
/**
|
|
275
275
|
* Graceful shutdown configuration for SIGINT/SIGTERM.
|
|
276
276
|
*
|
|
277
|
-
* When a persistent
|
|
277
|
+
* When a persistent node is running (Mode A, started via `registry.start()`),
|
|
278
278
|
* rivetkit installs Node SIGINT/SIGTERM handlers that call into core's
|
|
279
|
-
* `shutdown()` and wait up to `gracePeriodMs` for the
|
|
279
|
+
* `shutdown()` and wait up to `gracePeriodMs` for the node to drain
|
|
280
280
|
* before re-raising the signal to let Node exit via its default path.
|
|
281
281
|
*
|
|
282
282
|
* Handlers are NOT installed when `handler(request)` is used alone
|
|
@@ -289,9 +289,11 @@ export const RegistryConfigSchema = z
|
|
|
289
289
|
/**
|
|
290
290
|
* Wait this many milliseconds for the serve promise to resolve
|
|
291
291
|
* after calling `CoreRegistry::shutdown()`. Defaults to the
|
|
292
|
-
* engine-provided actor stop threshold once the
|
|
292
|
+
* engine-provided actor stop threshold once the node connects. A
|
|
293
|
+
* signal-driven shutdown of a managed local development engine waits
|
|
294
|
+
* one second by default so a file watcher can restart promptly.
|
|
293
295
|
*
|
|
294
|
-
*
|
|
296
|
+
* Set a longer period when a complete graceful node drain is required.
|
|
295
297
|
*/
|
|
296
298
|
gracePeriodMs: z.number().int().min(1_000).optional(),
|
|
297
299
|
/**
|
|
@@ -348,12 +350,12 @@ export const RegistryConfigSchema = z
|
|
|
348
350
|
});
|
|
349
351
|
}
|
|
350
352
|
|
|
351
|
-
//
|
|
352
|
-
if (config.configurePool
|
|
353
|
+
// Serverless pool configuration is disabled for v3.
|
|
354
|
+
if (config.configurePool) {
|
|
353
355
|
ctx.addIssue({
|
|
354
356
|
code: "custom",
|
|
355
|
-
message:
|
|
356
|
-
|
|
357
|
+
message: "serverless is disabled in this version",
|
|
358
|
+
path: ["configurePool"],
|
|
357
359
|
});
|
|
358
360
|
}
|
|
359
361
|
|
|
@@ -366,13 +368,7 @@ export const RegistryConfigSchema = z
|
|
|
366
368
|
? localEngineEndpoint
|
|
367
369
|
: (parsedEndpoint?.endpoint ??
|
|
368
370
|
(isDevEnv ? localEngineEndpoint : undefined));
|
|
369
|
-
|
|
370
|
-
// follows the same local-endpoint decision that causes core to manage the
|
|
371
|
-
// Engine, while explicit config and RIVET_RUN_SERVICES take precedence.
|
|
372
|
-
const startServices =
|
|
373
|
-
config.startServices ??
|
|
374
|
-
getRivetRunServices() ??
|
|
375
|
-
Boolean(endpoint && isLocalEngineEndpoint(endpoint));
|
|
371
|
+
const startServices = config.startServices ?? getRivetRunServices();
|
|
376
372
|
const validateServerlessEndpoint = Boolean(
|
|
377
373
|
config.startEngine || parsedEndpoint,
|
|
378
374
|
);
|
|
@@ -422,6 +418,7 @@ export const RegistryConfigSchema = z
|
|
|
422
418
|
...config,
|
|
423
419
|
sqlite,
|
|
424
420
|
endpoint,
|
|
421
|
+
engineSpawn: !parsedEndpoint && Boolean(endpoint),
|
|
425
422
|
startServices,
|
|
426
423
|
namespace,
|
|
427
424
|
token,
|
|
@@ -468,10 +465,10 @@ export function buildActorNames(
|
|
|
468
465
|
|
|
469
466
|
export const DocConfigurePoolSchema = z
|
|
470
467
|
.object({
|
|
471
|
-
name: z.string().optional().describe("Name of the
|
|
468
|
+
name: z.string().optional().describe("Name of the node pool."),
|
|
472
469
|
url: z
|
|
473
470
|
.string()
|
|
474
|
-
.describe("URL of the serverless platform to configure
|
|
471
|
+
.describe("URL of the serverless platform to configure nodes."),
|
|
475
472
|
headers: z
|
|
476
473
|
.record(z.string(), z.string())
|
|
477
474
|
.optional()
|
|
@@ -504,7 +501,7 @@ export const DocConfigurePoolSchema = z
|
|
|
504
501
|
.boolean()
|
|
505
502
|
.optional()
|
|
506
503
|
.describe(
|
|
507
|
-
"Drain
|
|
504
|
+
"Drain nodes when a new version is deployed. Defaults to true.",
|
|
508
505
|
),
|
|
509
506
|
})
|
|
510
507
|
.optional();
|
|
@@ -547,17 +544,17 @@ export const DocEnvoyConfigSchema = z
|
|
|
547
544
|
poolName: z
|
|
548
545
|
.string()
|
|
549
546
|
.optional()
|
|
550
|
-
.describe("Name of this
|
|
551
|
-
|
|
547
|
+
.describe("Name of this node pool. Default: 'default'"),
|
|
548
|
+
nodeKey: z
|
|
552
549
|
.string()
|
|
553
550
|
.optional()
|
|
554
|
-
.describe("Deprecated. Authentication key for the
|
|
551
|
+
.describe("Deprecated. Authentication key for the node."),
|
|
555
552
|
version: z
|
|
556
553
|
.number()
|
|
557
554
|
.optional()
|
|
558
|
-
.describe("Version number of this
|
|
555
|
+
.describe("Version number of this node. Default: 1"),
|
|
559
556
|
})
|
|
560
|
-
.describe("Configuration for
|
|
557
|
+
.describe("Configuration for node mode.");
|
|
561
558
|
|
|
562
559
|
export const DocSqliteConfigSchema = z
|
|
563
560
|
.object({
|
|
@@ -658,12 +655,12 @@ export const DocRegistryConfigSchema = z
|
|
|
658
655
|
.boolean()
|
|
659
656
|
.optional()
|
|
660
657
|
.describe(
|
|
661
|
-
"Starts Services when RivetKit manages a local Engine.
|
|
658
|
+
"Starts Services when RivetKit manages a local Engine. Disabled by default. Set RIVET_RUN_SERVICES=1 or startServices: true to enable.",
|
|
662
659
|
),
|
|
663
660
|
configurePool: DocConfigurePoolSchema.describe(
|
|
664
|
-
"Automatically configure serverless
|
|
661
|
+
"Automatically configure serverless nodes in the engine.",
|
|
665
662
|
),
|
|
666
663
|
serverless: DocServerlessConfigSchema.optional(),
|
|
667
|
-
|
|
664
|
+
node: DocEnvoyConfigSchema.optional(),
|
|
668
665
|
})
|
|
669
666
|
.describe("RivetKit registry configuration.");
|
package/src/registry/index.ts
CHANGED
|
@@ -30,6 +30,11 @@ type ShutdownSignal = "SIGINT" | "SIGTERM";
|
|
|
30
30
|
|
|
31
31
|
const REGISTRY_READY_TIMEOUT_MS = 30_000;
|
|
32
32
|
|
|
33
|
+
// Serverless is disabled for v3; keep the implementation for a later release.
|
|
34
|
+
function rejectServerless(): void {
|
|
35
|
+
throw new Error("serverless is disabled in this version");
|
|
36
|
+
}
|
|
37
|
+
|
|
33
38
|
function signalExitCode(signal: ShutdownSignal): number {
|
|
34
39
|
switch (signal) {
|
|
35
40
|
case "SIGINT":
|
|
@@ -190,6 +195,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
190
195
|
config: RegistryConfig,
|
|
191
196
|
): Promise<void> | undefined {
|
|
192
197
|
if (!config.configurePool) return undefined;
|
|
198
|
+
rejectServerless();
|
|
193
199
|
|
|
194
200
|
if (!this.#configureServerlessPoolPromise) {
|
|
195
201
|
this.#configureServerlessPoolPromise = configureServerlessPool(
|
|
@@ -215,6 +221,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
215
221
|
* ```
|
|
216
222
|
*/
|
|
217
223
|
public async handler(request: Request): Promise<Response> {
|
|
224
|
+
rejectServerless();
|
|
218
225
|
const config = this.parseConfig();
|
|
219
226
|
this.#printWelcome(config, "serverless");
|
|
220
227
|
|
|
@@ -413,6 +420,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
413
420
|
* ```
|
|
414
421
|
*/
|
|
415
422
|
public serve(): ServerlessHandler {
|
|
423
|
+
rejectServerless();
|
|
416
424
|
return {
|
|
417
425
|
fetch: (request) => this.handler(request),
|
|
418
426
|
};
|
|
@@ -438,6 +446,9 @@ export class Registry<A extends RegistryActors> {
|
|
|
438
446
|
* ```
|
|
439
447
|
*/
|
|
440
448
|
public async listen(opts: RegistryListenOptions = {}): Promise<void> {
|
|
449
|
+
if (!opts.application) {
|
|
450
|
+
rejectServerless();
|
|
451
|
+
}
|
|
441
452
|
const port = opts.port ?? parsePortEnv(process.env.RIVET_PORT) ?? 3000;
|
|
442
453
|
const publicDir = opts.publicDir ?? getRivetkitPublicDir();
|
|
443
454
|
const config = this.parseConfig();
|
|
@@ -554,6 +565,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
554
565
|
* Returns serverless metadata suitable for mounting in a user-owned router.
|
|
555
566
|
*/
|
|
556
567
|
async #metadataRoute(): Promise<Response> {
|
|
568
|
+
rejectServerless();
|
|
557
569
|
const configured = await this.#activeConfiguredRegistry();
|
|
558
570
|
if (!configured) {
|
|
559
571
|
return new Response("registry not started\n", {
|
|
@@ -626,7 +638,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
626
638
|
*/
|
|
627
639
|
#startEnvoy(config: RegistryConfig, printWelcome: boolean) {
|
|
628
640
|
if (!this.#runtimeServePromise) {
|
|
629
|
-
const configuredEnvoyVersion = this.#config.
|
|
641
|
+
const configuredEnvoyVersion = this.#config.node?.version;
|
|
630
642
|
const envoyVersionSource =
|
|
631
643
|
configuredEnvoyVersion !== undefined
|
|
632
644
|
? "config"
|
|
@@ -637,7 +649,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
637
649
|
logger().info({
|
|
638
650
|
msg: "starting rivetkit envoy",
|
|
639
651
|
rivetkitVersion: VERSION,
|
|
640
|
-
envoyVersion: config.
|
|
652
|
+
envoyVersion: config.node.version,
|
|
641
653
|
envoyVersionSource,
|
|
642
654
|
});
|
|
643
655
|
|
|
@@ -646,8 +658,8 @@ export class Registry<A extends RegistryActors> {
|
|
|
646
658
|
getNodeEnv() === "production"
|
|
647
659
|
) {
|
|
648
660
|
logger().error({
|
|
649
|
-
msg: "
|
|
650
|
-
envoyVersion: config.
|
|
661
|
+
msg: "node version defaulted because neither config.node.version nor RIVET_NODE_VERSION is set; actors will not drain automatically across deploys. See https://rivet.dev/docs/actors/versions",
|
|
662
|
+
envoyVersion: config.node.version,
|
|
651
663
|
envoyVersionSource,
|
|
652
664
|
});
|
|
653
665
|
}
|
|
@@ -666,7 +678,13 @@ export class Registry<A extends RegistryActors> {
|
|
|
666
678
|
// rejection unhandled. Downstream awaits (e.g. #runShutdown's
|
|
667
679
|
// Promise.race) attach their own catches and still observe
|
|
668
680
|
// resolution via the race.
|
|
669
|
-
logger().
|
|
681
|
+
logger().error({ error }, "runtime registry serve errored");
|
|
682
|
+
if (
|
|
683
|
+
typeof process !== "undefined" &&
|
|
684
|
+
typeof process.exit === "function"
|
|
685
|
+
) {
|
|
686
|
+
process.exit(1);
|
|
687
|
+
}
|
|
670
688
|
});
|
|
671
689
|
// Install signal handlers once an envoy lifecycle has begun. Only
|
|
672
690
|
// Mode A ever reaches here. Mode B (handler(request)) intentionally
|
|
@@ -714,7 +732,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
714
732
|
finishShutdownSignal(signal);
|
|
715
733
|
return;
|
|
716
734
|
}
|
|
717
|
-
this.#shutdownInFlight = this.#drain(config)
|
|
735
|
+
this.#shutdownInFlight = this.#drain(config, true)
|
|
718
736
|
.catch((err) => {
|
|
719
737
|
logger().warn({ err }, "shutdown error");
|
|
720
738
|
})
|
|
@@ -757,18 +775,28 @@ export class Registry<A extends RegistryActors> {
|
|
|
757
775
|
return this.#shutdownInFlight;
|
|
758
776
|
}
|
|
759
777
|
|
|
760
|
-
async #drain(config: RegistryConfig): Promise<void> {
|
|
778
|
+
async #drain(config: RegistryConfig, signalDriven = false): Promise<void> {
|
|
761
779
|
const modeAPromise = this.#runtimeServeConfiguredPromise;
|
|
762
780
|
const modeBPromise = this.#runtimeServerlessPromise;
|
|
763
781
|
const runtimes = new Set<CoreRuntime>();
|
|
764
782
|
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
(
|
|
768
|
-
|
|
783
|
+
const localDevSignal =
|
|
784
|
+
signalDriven &&
|
|
785
|
+
getNodeEnv() !== "production" &&
|
|
786
|
+
config.engineSpawn &&
|
|
787
|
+
config.endpoint !== undefined &&
|
|
788
|
+
isLocalEngineEndpoint(config.endpoint);
|
|
789
|
+
let gracePeriodMs = config.shutdown?.gracePeriodMs;
|
|
790
|
+
if (gracePeriodMs === undefined) {
|
|
791
|
+
gracePeriodMs = localDevSignal
|
|
792
|
+
? 1_000
|
|
793
|
+
: ((await this.#actorStopThresholdMs(
|
|
794
|
+
modeAPromise ?? modeBPromise,
|
|
795
|
+
)) ?? 30 * 60 * 1000);
|
|
796
|
+
}
|
|
769
797
|
// Race the entire drain sequence (both modes + serve promise) against
|
|
770
|
-
// a single grace ceiling.
|
|
771
|
-
//
|
|
798
|
+
// a single grace ceiling. Local dev signal shutdowns allow the watcher
|
|
799
|
+
// to restart promptly; other shutdowns use the engine's actor stop threshold.
|
|
772
800
|
const drain = async () => {
|
|
773
801
|
// Shut down every live `CoreRegistry` we know about. Mode A
|
|
774
802
|
// (`start()`) and Mode B (`handler()`) each build a separate
|
|
@@ -887,12 +915,16 @@ export class Registry<A extends RegistryActors> {
|
|
|
887
915
|
);
|
|
888
916
|
}
|
|
889
917
|
if (this.#runtimeReadyPromise) return this.#runtimeReadyPromise;
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
918
|
+
try {
|
|
919
|
+
if (getRivetkitRuntimeMode() === "serverless") {
|
|
920
|
+
return Promise.reject(
|
|
921
|
+
new Error(
|
|
922
|
+
"registry.startAndWait() requires envoy runtime mode; serverless registries become ready per request",
|
|
923
|
+
),
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
} catch (error) {
|
|
927
|
+
return Promise.reject(error);
|
|
896
928
|
}
|
|
897
929
|
|
|
898
930
|
const config = this.parseConfig();
|
|
@@ -481,8 +481,9 @@ export class NapiCoreRuntime implements CoreRuntime {
|
|
|
481
481
|
onCancellationTokenCancelled(
|
|
482
482
|
token: CancellationTokenHandle,
|
|
483
483
|
callback: (...args: unknown[]) => unknown,
|
|
484
|
-
): void {
|
|
485
|
-
asNativeCancellationToken(token).onCancelled(callback);
|
|
484
|
+
): () => void {
|
|
485
|
+
const listener = asNativeCancellationToken(token).onCancelled(callback);
|
|
486
|
+
return () => listener.release();
|
|
486
487
|
}
|
|
487
488
|
|
|
488
489
|
actorState(ctx: ActorContextHandle): Buffer {
|
package/src/registry/native.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "@/actor/config";
|
|
27
27
|
import type { AnyActorDefinition } from "@/actor/definition";
|
|
28
28
|
import {
|
|
29
|
+
actorStopping,
|
|
29
30
|
decodeBridgeRivetError,
|
|
30
31
|
encodeBridgeRivetError,
|
|
31
32
|
forbiddenError,
|
|
@@ -126,6 +127,7 @@ import type {
|
|
|
126
127
|
RuntimeStateDeltaPayload,
|
|
127
128
|
WebSocketHandle,
|
|
128
129
|
} from "./runtime";
|
|
130
|
+
import { servicesBinaryUnavailable } from "./runtime";
|
|
129
131
|
import { loadWasmRuntime } from "./wasm-runtime";
|
|
130
132
|
import {
|
|
131
133
|
createWriteThroughProxy,
|
|
@@ -347,6 +349,11 @@ type NativeDestroyGate = {
|
|
|
347
349
|
type NativeDatabaseClientState = {
|
|
348
350
|
client: unknown;
|
|
349
351
|
};
|
|
352
|
+
type NativeActorAbort = {
|
|
353
|
+
signal: AbortSignal;
|
|
354
|
+
listeners: Set<() => void>;
|
|
355
|
+
};
|
|
356
|
+
|
|
350
357
|
type NativeActorRuntimeState = {
|
|
351
358
|
sql?: ReturnType<typeof wrapJsNativeDatabase>;
|
|
352
359
|
databaseClient?: NativeDatabaseClientState;
|
|
@@ -354,6 +361,17 @@ type NativeActorRuntimeState = {
|
|
|
354
361
|
vars?: unknown;
|
|
355
362
|
destroyGate?: NativeDestroyGate;
|
|
356
363
|
persistState?: NativePersistActorState;
|
|
364
|
+
// One native actor abort signal shared by every context of the actor. Each
|
|
365
|
+
// native signal parks a task and a callback handle until the actor stops,
|
|
366
|
+
// so creating one per request or action leaks both. Per-context listeners
|
|
367
|
+
// live in `listeners` so the shared signal never collects one listener per
|
|
368
|
+
// in-flight request.
|
|
369
|
+
actorAbort?: NativeActorAbort;
|
|
370
|
+
// Set once shutdown cleanup has cleared this generation's caches. Work that
|
|
371
|
+
// outlives the generation, such as an untracked timer or a late WebSocket
|
|
372
|
+
// message handler, then fails with `actor.stopping` instead of reading an
|
|
373
|
+
// empty bag as if `vars` or the database were never initialized.
|
|
374
|
+
cleared?: true;
|
|
357
375
|
};
|
|
358
376
|
|
|
359
377
|
// Keep JS-only actor caches on the NAPI ActorContext runtime-state bag instead
|
|
@@ -363,9 +381,10 @@ function getNativeRuntimeState(
|
|
|
363
381
|
runtime: CoreRuntime,
|
|
364
382
|
ctx: ActorContextHandle,
|
|
365
383
|
): NativeActorRuntimeState {
|
|
366
|
-
const runtimeState =
|
|
367
|
-
|
|
368
|
-
|
|
384
|
+
const runtimeState = readNativeRuntimeStateBag(runtime, ctx);
|
|
385
|
+
if (runtimeState.cleared) {
|
|
386
|
+
throw actorStopping(callNativeSync(() => runtime.actorId(ctx)));
|
|
387
|
+
}
|
|
369
388
|
if (!runtimeState.destroyGate) {
|
|
370
389
|
runtimeState.destroyGate = {};
|
|
371
390
|
}
|
|
@@ -379,6 +398,22 @@ function getNativeRuntimeState(
|
|
|
379
398
|
return runtimeState;
|
|
380
399
|
}
|
|
381
400
|
|
|
401
|
+
function readNativeRuntimeStateBag(
|
|
402
|
+
runtime: CoreRuntime,
|
|
403
|
+
ctx: ActorContextHandle,
|
|
404
|
+
): NativeActorRuntimeState {
|
|
405
|
+
return callNativeSync(() =>
|
|
406
|
+
runtime.actorRuntimeState(ctx),
|
|
407
|
+
) as NativeActorRuntimeState;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function isNativeRuntimeStateCleared(
|
|
411
|
+
runtime: CoreRuntime,
|
|
412
|
+
ctx: ActorContextHandle,
|
|
413
|
+
): boolean {
|
|
414
|
+
return readNativeRuntimeStateBag(runtime, ctx).cleared === true;
|
|
415
|
+
}
|
|
416
|
+
|
|
382
417
|
function getNativePersistState(
|
|
383
418
|
runtime: CoreRuntime,
|
|
384
419
|
ctx: ActorContextHandle,
|
|
@@ -521,7 +556,18 @@ function clearNativeRuntimeState(
|
|
|
521
556
|
runtime: CoreRuntime,
|
|
522
557
|
ctx: ActorContextHandle,
|
|
523
558
|
) {
|
|
559
|
+
// A coalesced save armed before the clear would otherwise fire against the
|
|
560
|
+
// cleared bag and throw outside any caller.
|
|
561
|
+
const pendingSaveHandle = readNativeRuntimeStateBag(runtime, ctx)
|
|
562
|
+
.persistState?.pendingSaveHandle;
|
|
563
|
+
if (pendingSaveHandle !== undefined) {
|
|
564
|
+
clearImmediate(pendingSaveHandle);
|
|
565
|
+
}
|
|
524
566
|
callNativeSync(() => runtime.actorClearRuntimeState(ctx));
|
|
567
|
+
// The runtime hands out a fresh bag after a clear. Each generation has its
|
|
568
|
+
// own bag, so marking it makes later access from this generation fail typed
|
|
569
|
+
// without touching any newer generation of the same actor.
|
|
570
|
+
readNativeRuntimeStateBag(runtime, ctx).cleared = true;
|
|
525
571
|
}
|
|
526
572
|
|
|
527
573
|
async function cleanupNativeSleepRuntimeState(
|
|
@@ -536,8 +582,7 @@ async function cleanupNativeSleepRuntimeState(
|
|
|
536
582
|
// the tracked work finishes without a deadline.
|
|
537
583
|
const drained = await runtime.actorWaitForTrackedShutdownWork(ctx);
|
|
538
584
|
if (!drained) {
|
|
539
|
-
await
|
|
540
|
-
await closeNativeSqlDatabase(runtime, ctx);
|
|
585
|
+
await detachNativeDatabaseForShutdown(runtime, ctx);
|
|
541
586
|
void runtime
|
|
542
587
|
.actorWaitForTrackedShutdownWorkUnbounded(ctx)
|
|
543
588
|
.then(async () => {
|
|
@@ -554,11 +599,26 @@ async function cleanupNativeSleepRuntimeState(
|
|
|
554
599
|
}
|
|
555
600
|
|
|
556
601
|
await afterTrackedWorkDrained?.();
|
|
557
|
-
await
|
|
558
|
-
await closeNativeSqlDatabase(runtime, ctx);
|
|
602
|
+
await detachNativeDatabaseForShutdown(runtime, ctx);
|
|
559
603
|
clearNativeRuntimeState(runtime, ctx);
|
|
560
604
|
}
|
|
561
605
|
|
|
606
|
+
async function detachNativeDatabaseForShutdown(
|
|
607
|
+
runtime: CoreRuntime,
|
|
608
|
+
ctx: ActorContextHandle,
|
|
609
|
+
): Promise<void> {
|
|
610
|
+
const runtimeState = getNativeRuntimeState(runtime, ctx);
|
|
611
|
+
// Stop JS access without closing the runtime-owned SQLite backend. Rust still
|
|
612
|
+
// needs it to reconcile scheduled alarms and performs the physical close after
|
|
613
|
+
// this lifecycle callback returns.
|
|
614
|
+
await runtimeState.sql?.detachForShutdown();
|
|
615
|
+
try {
|
|
616
|
+
await closeNativeDatabaseClient(runtime, ctx);
|
|
617
|
+
} finally {
|
|
618
|
+
runtimeState.sql = undefined;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
562
622
|
function closeNativeSqlDatabase(
|
|
563
623
|
runtime: CoreRuntime,
|
|
564
624
|
ctx: ActorContextHandle,
|
|
@@ -784,7 +844,7 @@ async function loadEngineCli(): Promise<typeof import("@rivetkit/engine-cli")> {
|
|
|
784
844
|
return import(["@rivetkit", "engine-cli"].join("/"));
|
|
785
845
|
}
|
|
786
846
|
|
|
787
|
-
async function loadServices(): Promise<
|
|
847
|
+
async function loadServices(): Promise<{ getServicesPath: () => string }> {
|
|
788
848
|
// Keep the native binary opaque to edge bundlers for the same reason as
|
|
789
849
|
// engine-cli above.
|
|
790
850
|
return import(["@rivet-dev", "services"].join("/"));
|
|
@@ -3022,22 +3082,28 @@ export class ActorContextHandleAdapter {
|
|
|
3022
3082
|
|
|
3023
3083
|
get abortSignal(): AbortSignal {
|
|
3024
3084
|
if (!this.#abortSignal) {
|
|
3025
|
-
const
|
|
3085
|
+
const actorAbort = this.#actorAbort();
|
|
3086
|
+
const actorSignal = actorAbort.signal;
|
|
3026
3087
|
if (this.#dispatchCancelToken === undefined) {
|
|
3027
3088
|
this.#abortSignal = actorSignal;
|
|
3028
3089
|
} else {
|
|
3029
3090
|
const controller = new AbortController();
|
|
3030
3091
|
let cleanedUp = false;
|
|
3092
|
+
let releaseDispatchListener: (() => void) | undefined;
|
|
3031
3093
|
const onActorAbort = () => {
|
|
3032
3094
|
cleanup();
|
|
3033
3095
|
controller.abort();
|
|
3034
3096
|
};
|
|
3097
|
+
// Releasing the native listener on dispose frees it even when the
|
|
3098
|
+
// dispatch token is never cancelled.
|
|
3035
3099
|
const cleanup = () => {
|
|
3036
3100
|
if (cleanedUp) {
|
|
3037
3101
|
return;
|
|
3038
3102
|
}
|
|
3039
3103
|
cleanedUp = true;
|
|
3040
|
-
|
|
3104
|
+
actorAbort.listeners.delete(onActorAbort);
|
|
3105
|
+
releaseDispatchListener?.();
|
|
3106
|
+
releaseDispatchListener = undefined;
|
|
3041
3107
|
this.#abortSignalCleanup = undefined;
|
|
3042
3108
|
};
|
|
3043
3109
|
|
|
@@ -3051,10 +3117,8 @@ export class ActorContextHandleAdapter {
|
|
|
3051
3117
|
} else {
|
|
3052
3118
|
const dispatchCancelToken = this.#dispatchCancelToken;
|
|
3053
3119
|
this.#abortSignalCleanup = cleanup;
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
});
|
|
3057
|
-
callNativeSync(() =>
|
|
3120
|
+
actorAbort.listeners.add(onActorAbort);
|
|
3121
|
+
releaseDispatchListener = callNativeSync(() =>
|
|
3058
3122
|
this.#runtime.onCancellationTokenCancelled(
|
|
3059
3123
|
dispatchCancelToken,
|
|
3060
3124
|
() => {
|
|
@@ -3506,24 +3570,49 @@ export class ActorContextHandleAdapter {
|
|
|
3506
3570
|
|
|
3507
3571
|
async dispose(): Promise<void> {
|
|
3508
3572
|
// Flush any save coalesced for this tick before the context is torn
|
|
3509
|
-
// down so the request-save and onStateChange always run.
|
|
3510
|
-
|
|
3573
|
+
// down so the request-save and onStateChange always run. Shutdown
|
|
3574
|
+
// cleanup may already have cleared the generation, which leaves no
|
|
3575
|
+
// pending save to flush.
|
|
3576
|
+
if (!isNativeRuntimeStateCleared(this.#runtime, this.#ctx)) {
|
|
3577
|
+
this.#flushStateChange();
|
|
3578
|
+
}
|
|
3511
3579
|
this.#abortSignalCleanup?.();
|
|
3512
3580
|
}
|
|
3513
3581
|
|
|
3514
|
-
#
|
|
3582
|
+
#actorAbort(): NativeActorAbort {
|
|
3583
|
+
// An aborted cached signal may belong to a previous generation, so
|
|
3584
|
+
// only a live one is reused.
|
|
3585
|
+
const runtimeState = readNativeRuntimeStateBag(
|
|
3586
|
+
this.#runtime,
|
|
3587
|
+
this.#ctx,
|
|
3588
|
+
);
|
|
3589
|
+
const cached = runtimeState.actorAbort;
|
|
3590
|
+
if (cached && !cached.signal.aborted) {
|
|
3591
|
+
return cached;
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3515
3594
|
const nativeSignal = callNativeSync(() =>
|
|
3516
3595
|
this.#runtime.actorAbortSignal(this.#ctx),
|
|
3517
3596
|
);
|
|
3518
3597
|
const controller = new AbortController();
|
|
3519
|
-
|
|
3598
|
+
const actorAbort: NativeActorAbort = {
|
|
3599
|
+
signal: controller.signal,
|
|
3600
|
+
listeners: new Set(),
|
|
3601
|
+
};
|
|
3602
|
+
const abort = () => {
|
|
3520
3603
|
controller.abort();
|
|
3604
|
+
for (const listener of actorAbort.listeners) {
|
|
3605
|
+
listener();
|
|
3606
|
+
}
|
|
3607
|
+
actorAbort.listeners.clear();
|
|
3608
|
+
};
|
|
3609
|
+
if (nativeSignal.aborted) {
|
|
3610
|
+
abort();
|
|
3521
3611
|
} else {
|
|
3522
|
-
nativeSignal.addEventListener("abort",
|
|
3523
|
-
once: true,
|
|
3524
|
-
});
|
|
3612
|
+
nativeSignal.addEventListener("abort", abort, { once: true });
|
|
3525
3613
|
}
|
|
3526
|
-
|
|
3614
|
+
runtimeState.actorAbort = actorAbort;
|
|
3615
|
+
return actorAbort;
|
|
3527
3616
|
}
|
|
3528
3617
|
|
|
3529
3618
|
#readState(): unknown {
|
|
@@ -4846,7 +4935,7 @@ export function buildNativeFactory(
|
|
|
4846
4935
|
}
|
|
4847
4936
|
} finally {
|
|
4848
4937
|
resolveNativeDestroy(runtime, ctx);
|
|
4849
|
-
await
|
|
4938
|
+
await detachNativeDatabaseForShutdown(runtime, ctx);
|
|
4850
4939
|
clearNativeRuntimeState(runtime, ctx);
|
|
4851
4940
|
await actorCtx.dispose();
|
|
4852
4941
|
}
|
|
@@ -5598,11 +5687,12 @@ export async function buildServeConfig(
|
|
|
5598
5687
|
}
|
|
5599
5688
|
|
|
5600
5689
|
const serveConfig: RuntimeServeConfig = {
|
|
5601
|
-
version: config.
|
|
5690
|
+
version: config.node.version,
|
|
5602
5691
|
endpoint: config.endpoint,
|
|
5692
|
+
engineSpawn: config.engineSpawn,
|
|
5603
5693
|
token: config.token,
|
|
5604
5694
|
namespace: config.namespace,
|
|
5605
|
-
poolName: config.
|
|
5695
|
+
poolName: config.node.poolName,
|
|
5606
5696
|
startServices: resolveServicesBinary && config.startServices,
|
|
5607
5697
|
handleInspectorHttpInRuntime: true,
|
|
5608
5698
|
serverlessBasePath: config.serverless.basePath,
|
|
@@ -5616,7 +5706,7 @@ export async function buildServeConfig(
|
|
|
5616
5706
|
|
|
5617
5707
|
// Always best-effort resolve the npm-installed engine binary and hand its
|
|
5618
5708
|
// path to the core. The core alone decides whether to actually spawn a local
|
|
5619
|
-
// engine
|
|
5709
|
+
// engine using the resolved spawn decision, so
|
|
5620
5710
|
// JS must not duplicate that decision here. Only JS knows the npm
|
|
5621
5711
|
// `node_modules` layout, so it resolves the path; if no binary is available
|
|
5622
5712
|
// (remote-only install, unsupported platform, optional deps skipped), leave
|
|
@@ -5636,14 +5726,16 @@ export async function buildServeConfig(
|
|
|
5636
5726
|
});
|
|
5637
5727
|
}
|
|
5638
5728
|
if (resolveServicesBinary && config.startServices) {
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
serveConfig.servicesBinaryPath =
|
|
5642
|
-
}
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
})
|
|
5729
|
+
const servicesBinary = getEnvUniversal("RIVET_SERVICES_BINARY");
|
|
5730
|
+
if (servicesBinary) {
|
|
5731
|
+
serveConfig.servicesBinaryPath = servicesBinary;
|
|
5732
|
+
} else {
|
|
5733
|
+
try {
|
|
5734
|
+
const { getServicesPath } = await loadServices();
|
|
5735
|
+
serveConfig.servicesBinaryPath = getServicesPath();
|
|
5736
|
+
} catch (error) {
|
|
5737
|
+
throw servicesBinaryUnavailable(error);
|
|
5738
|
+
}
|
|
5647
5739
|
}
|
|
5648
5740
|
}
|
|
5649
5741
|
serveConfig.engineHost = config.engineHost;
|