rivetkit 2.0.42 → 2.1.0-rc.1
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/{tsup/config-CLnylLYY.d.ts → browser/client.d.ts} +2127 -1910
- package/dist/browser/client.js +5182 -0
- package/dist/browser/client.js.map +1 -0
- package/dist/browser/inspector/client.d.ts +130 -0
- package/dist/browser/inspector/client.js +2854 -0
- package/dist/browser/inspector/client.js.map +1 -0
- package/dist/browser/v3-DnYObHH3.d.ts +279 -0
- package/dist/schemas/actor-inspector/v2.ts +796 -0
- package/dist/schemas/actor-inspector/v3.ts +899 -0
- package/dist/schemas/actor-persist/v4.ts +406 -0
- package/dist/schemas/client-protocol/v3.ts +554 -0
- package/dist/schemas/persist/v1.ts +781 -0
- package/dist/schemas/transport/v1.ts +697 -0
- package/dist/tsup/actor/errors.cjs +27 -3
- package/dist/tsup/actor/errors.cjs.map +1 -1
- package/dist/tsup/actor/errors.d.cts +37 -1
- package/dist/tsup/actor/errors.d.ts +37 -1
- package/dist/tsup/actor/errors.js +26 -1
- package/dist/tsup/{actor-router-consts-DzI2szci.d.cts → actor-router-consts-D29T1Z-K.d.cts} +1 -1
- package/dist/tsup/{actor-router-consts-DzI2szci.d.ts → actor-router-consts-D29T1Z-K.d.ts} +1 -1
- package/dist/tsup/chunk-424PT5DM.js +23 -0
- package/dist/tsup/chunk-424PT5DM.js.map +1 -0
- package/dist/tsup/{chunk-JDAD2YFA.js → chunk-5ESWDTHJ.js} +148 -273
- package/dist/tsup/chunk-5ESWDTHJ.js.map +1 -0
- package/dist/tsup/{chunk-FJ3KTN4V.js → chunk-6LIBPELE.js} +119 -11
- package/dist/tsup/chunk-6LIBPELE.js.map +1 -0
- package/dist/tsup/chunk-6LJAZ5R4.cjs +96 -0
- package/dist/tsup/chunk-6LJAZ5R4.cjs.map +1 -0
- package/dist/tsup/{chunk-LFVF5SCU.js → chunk-7HTNH26M.js} +126 -1
- package/dist/tsup/chunk-7HTNH26M.js.map +1 -0
- package/dist/tsup/chunk-7K4CYDGD.js +630 -0
- package/dist/tsup/chunk-7K4CYDGD.js.map +1 -0
- package/dist/tsup/{chunk-XXGJCOL6.js → chunk-A6YIZWTK.js} +2 -2
- package/dist/tsup/chunk-AIYEYMX5.cjs +630 -0
- package/dist/tsup/chunk-AIYEYMX5.cjs.map +1 -0
- package/dist/tsup/{chunk-Q6W7RJJP.js → chunk-DIGBC2VI.js} +211 -2316
- package/dist/tsup/chunk-DIGBC2VI.js.map +1 -0
- package/dist/tsup/{chunk-RZW2DNND.cjs → chunk-F6JYU5IK.cjs} +1957 -1039
- package/dist/tsup/chunk-F6JYU5IK.cjs.map +1 -0
- package/dist/tsup/chunk-HAZL2EPK.cjs +534 -0
- package/dist/tsup/chunk-HAZL2EPK.cjs.map +1 -0
- package/dist/tsup/chunk-HDQ2JUQT.cjs +23 -0
- package/dist/tsup/chunk-HDQ2JUQT.cjs.map +1 -0
- package/dist/tsup/chunk-HIDX4C5Y.cjs +1036 -0
- package/dist/tsup/chunk-HIDX4C5Y.cjs.map +1 -0
- package/dist/tsup/chunk-IVG73YCW.js +534 -0
- package/dist/tsup/chunk-IVG73YCW.js.map +1 -0
- package/dist/tsup/chunk-KJSYAUOM.js +96 -0
- package/dist/tsup/chunk-KJSYAUOM.js.map +1 -0
- package/dist/tsup/{chunk-2XQS746M.cjs → chunk-L47L3ZWJ.cjs} +127 -2
- package/dist/tsup/chunk-L47L3ZWJ.cjs.map +1 -0
- package/dist/tsup/{chunk-H4TB4X25.cjs → chunk-LW6KLR7A.cjs} +126 -18
- package/dist/tsup/chunk-LW6KLR7A.cjs.map +1 -0
- package/dist/tsup/chunk-LXUQ667X.js +2006 -0
- package/dist/tsup/chunk-LXUQ667X.js.map +1 -0
- package/dist/tsup/{chunk-GMAVRZSF.js → chunk-M2T62AZQ.js} +1790 -872
- package/dist/tsup/chunk-M2T62AZQ.js.map +1 -0
- package/dist/tsup/chunk-MZ37VV3P.js +5974 -0
- package/dist/tsup/chunk-MZ37VV3P.js.map +1 -0
- package/dist/tsup/chunk-N4KRDJ56.js +72 -0
- package/dist/tsup/chunk-N4KRDJ56.js.map +1 -0
- package/dist/tsup/chunk-NIYZDWMW.cjs +2006 -0
- package/dist/tsup/chunk-NIYZDWMW.cjs.map +1 -0
- package/dist/tsup/chunk-OMEPCQK2.js +649 -0
- package/dist/tsup/chunk-OMEPCQK2.js.map +1 -0
- package/dist/tsup/chunk-SR3KQE7Q.cjs +72 -0
- package/dist/tsup/chunk-SR3KQE7Q.cjs.map +1 -0
- package/dist/tsup/chunk-SSEP6DHP.cjs +2657 -0
- package/dist/tsup/chunk-SSEP6DHP.cjs.map +1 -0
- package/dist/tsup/chunk-T5YCUGVS.js +1036 -0
- package/dist/tsup/chunk-T5YCUGVS.js.map +1 -0
- package/dist/tsup/{chunk-EJVBH5VF.cjs → chunk-TPGXWFQT.cjs} +3 -3
- package/dist/tsup/{chunk-EJVBH5VF.cjs.map → chunk-TPGXWFQT.cjs.map} +1 -1
- package/dist/tsup/{chunk-X35U3YNX.cjs → chunk-TYLXNCA5.cjs} +214 -339
- package/dist/tsup/chunk-TYLXNCA5.cjs.map +1 -0
- package/dist/tsup/chunk-VKVNIQRQ.js +257 -0
- package/dist/tsup/chunk-VKVNIQRQ.js.map +1 -0
- package/dist/tsup/chunk-XWBAQO5H.cjs +649 -0
- package/dist/tsup/chunk-XWBAQO5H.cjs.map +1 -0
- package/dist/tsup/chunk-YQ4LDVD6.cjs +5974 -0
- package/dist/tsup/chunk-YQ4LDVD6.cjs.map +1 -0
- package/dist/tsup/chunk-ZFY5J2EP.cjs +257 -0
- package/dist/tsup/chunk-ZFY5J2EP.cjs.map +1 -0
- package/dist/tsup/client/mod.cjs +9 -10
- package/dist/tsup/client/mod.cjs.map +1 -1
- package/dist/tsup/client/mod.d.cts +11 -5
- package/dist/tsup/client/mod.d.ts +11 -5
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +4 -4
- package/dist/tsup/common/log.d.cts +2 -2
- package/dist/tsup/common/log.d.ts +2 -2
- package/dist/tsup/common/log.js +3 -2
- package/dist/tsup/common/websocket.cjs +5 -5
- package/dist/tsup/common/websocket.js +4 -3
- package/dist/tsup/config-BFqid9Gr.d.ts +2574 -0
- package/dist/tsup/config-BiNoIHRs.d.cts +80 -0
- package/dist/tsup/config-BiNoIHRs.d.ts +80 -0
- package/dist/tsup/{config-CZB2-W8x.d.cts → config-CAZphOS1.d.cts} +681 -355
- package/dist/tsup/db/drizzle/mod.cjs +49 -0
- package/dist/tsup/db/drizzle/mod.cjs.map +1 -0
- package/dist/tsup/db/drizzle/mod.d.cts +17 -0
- package/dist/tsup/db/drizzle/mod.d.ts +17 -0
- package/dist/tsup/db/drizzle/mod.js +49 -0
- package/dist/tsup/db/drizzle/mod.js.map +1 -0
- package/dist/tsup/db/mod.cjs +9 -0
- package/dist/tsup/db/mod.cjs.map +1 -0
- package/dist/tsup/db/mod.d.cts +9 -0
- package/dist/tsup/db/mod.d.ts +9 -0
- package/dist/tsup/db/mod.js +9 -0
- package/dist/tsup/db/mod.js.map +1 -0
- package/dist/tsup/{driver-D0QX9M11.d.ts → driver-Bxv62E2p.d.ts} +2 -2
- package/dist/tsup/{driver-q-zqG7fc.d.cts → driver-DYXwJR5D.d.cts} +2 -2
- package/dist/tsup/driver-helpers/mod.cjs +12 -6
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
- package/dist/tsup/driver-helpers/mod.d.cts +12 -5
- package/dist/tsup/driver-helpers/mod.d.ts +12 -5
- package/dist/tsup/driver-helpers/mod.js +12 -5
- package/dist/tsup/driver-test-suite/mod.cjs +1370 -116
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/driver-test-suite/mod.d.cts +10 -4
- package/dist/tsup/driver-test-suite/mod.d.ts +10 -4
- package/dist/tsup/driver-test-suite/mod.js +2093 -838
- package/dist/tsup/driver-test-suite/mod.js.map +1 -1
- package/dist/tsup/inspector/mod.cjs +29 -3
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.d.cts +124 -3
- package/dist/tsup/inspector/mod.d.ts +124 -3
- package/dist/tsup/inspector/mod.js +72 -45
- package/dist/tsup/keys-CydblqMh.d.cts +13 -0
- package/dist/tsup/keys-CydblqMh.d.ts +13 -0
- package/dist/tsup/mod.cjs +16 -10
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +26 -14
- package/dist/tsup/mod.d.ts +26 -14
- package/dist/tsup/mod.js +20 -13
- package/dist/tsup/serve-test-suite/mod.cjs +1165 -83
- package/dist/tsup/serve-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/serve-test-suite/mod.js +1114 -29
- package/dist/tsup/serve-test-suite/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +84 -11
- package/dist/tsup/test/mod.cjs.map +1 -1
- package/dist/tsup/test/mod.d.cts +10 -5
- package/dist/tsup/test/mod.d.ts +10 -5
- package/dist/tsup/test/mod.js +85 -11
- package/dist/tsup/test/mod.js.map +1 -1
- package/dist/tsup/utils.cjs +10 -4
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +72 -2
- package/dist/tsup/utils.d.ts +72 -2
- package/dist/tsup/utils.js +9 -2
- package/dist/tsup/v3-DnYObHH3.d.cts +279 -0
- package/dist/tsup/v3-DnYObHH3.d.ts +279 -0
- package/dist/tsup/workflow/mod.cjs +16 -0
- package/dist/tsup/workflow/mod.cjs.map +1 -0
- package/dist/tsup/workflow/mod.d.cts +83 -0
- package/dist/tsup/workflow/mod.d.ts +83 -0
- package/dist/tsup/workflow/mod.js +16 -0
- package/dist/tsup/workflow/mod.js.map +1 -0
- package/package.json +62 -5
- package/src/actor/config.ts +478 -68
- package/src/actor/conn/mod.ts +68 -16
- package/src/actor/conn/state-manager.ts +2 -2
- package/src/actor/contexts/action.ts +20 -12
- package/src/actor/contexts/base/actor.ts +137 -7
- package/src/actor/contexts/base/conn-init.ts +27 -7
- package/src/actor/contexts/base/conn.ts +27 -18
- package/src/actor/contexts/before-action-response.ts +9 -2
- package/src/actor/contexts/before-connect.ts +7 -2
- package/src/actor/contexts/connect.ts +9 -2
- package/src/actor/contexts/create-conn-state.ts +7 -2
- package/src/actor/contexts/create-vars.ts +16 -3
- package/src/actor/contexts/create.ts +16 -3
- package/src/actor/contexts/destroy.ts +9 -3
- package/src/actor/contexts/disconnect.ts +10 -4
- package/src/actor/contexts/index.ts +4 -3
- package/src/actor/contexts/request.ts +23 -6
- package/src/actor/contexts/run.ts +47 -0
- package/src/actor/contexts/sleep.ts +9 -3
- package/src/actor/contexts/state-change.ts +9 -3
- package/src/actor/contexts/wake.ts +9 -3
- package/src/actor/contexts/websocket.ts +23 -6
- package/src/actor/database.ts +8 -18
- package/src/actor/definition.ts +20 -6
- package/src/actor/driver.ts +32 -3
- package/src/actor/errors.ts +127 -0
- package/src/actor/instance/connection-manager.ts +183 -80
- package/src/actor/instance/event-manager.ts +26 -15
- package/src/actor/instance/keys.ts +117 -0
- package/src/actor/instance/mod.ts +784 -174
- package/src/actor/instance/queue-manager.ts +603 -0
- package/src/actor/instance/queue.ts +287 -0
- package/src/actor/instance/schedule-manager.ts +49 -7
- package/src/actor/instance/state-manager.ts +35 -11
- package/src/actor/instance/traces-driver.ts +128 -0
- package/src/actor/mod.ts +26 -2
- package/src/actor/protocol/old.ts +28 -13
- package/src/actor/protocol/serde.ts +1 -1
- package/src/actor/router-endpoints.ts +177 -21
- package/src/actor/router-websocket-endpoints.ts +18 -29
- package/src/actor/router.ts +177 -0
- package/src/actor/schema.ts +291 -0
- package/src/actor/utils.ts +40 -0
- package/src/client/actor-common.ts +1 -1
- package/src/client/actor-conn.ts +100 -33
- package/src/client/actor-handle.ts +61 -33
- package/src/client/client.ts +2 -4
- package/src/client/config.ts +1 -1
- package/src/client/mod.browser.ts +2 -0
- package/src/client/mod.ts +1 -4
- package/src/client/queue.ts +146 -0
- package/src/client/utils.ts +1 -1
- package/src/common/log.ts +1 -1
- package/src/common/utils.ts +3 -3
- package/src/db/config.ts +100 -0
- package/src/db/drizzle/mod.ts +226 -0
- package/src/db/drizzle/sqlite-core.ts +22 -0
- package/src/db/mod.ts +125 -0
- package/src/db/shared.ts +92 -0
- package/src/db/sqlite-vfs.ts +12 -0
- package/src/driver-helpers/mod.ts +1 -0
- package/src/driver-test-suite/mod.ts +69 -43
- package/src/driver-test-suite/tests/access-control.ts +218 -0
- package/src/driver-test-suite/tests/actor-db-raw.ts +73 -0
- package/src/driver-test-suite/tests/actor-db.ts +394 -0
- package/src/driver-test-suite/tests/actor-inspector.ts +259 -358
- package/src/driver-test-suite/tests/actor-kv.ts +41 -20
- package/src/driver-test-suite/tests/actor-queue.ts +324 -0
- package/src/driver-test-suite/tests/actor-run.ts +181 -0
- package/src/driver-test-suite/tests/actor-schedule.ts +5 -2
- package/src/driver-test-suite/tests/actor-sleep.ts +3 -3
- package/src/driver-test-suite/tests/actor-stateless.ts +70 -0
- package/src/driver-test-suite/tests/actor-workflow.ts +108 -0
- package/src/driver-test-suite/tests/manager-driver.ts +11 -0
- package/src/driver-test-suite/tests/raw-http-request-properties.ts +1 -1
- package/src/driver-test-suite/tests/raw-websocket.ts +12 -12
- package/src/drivers/default.ts +7 -2
- package/src/drivers/engine/actor-driver.ts +45 -37
- package/src/drivers/engine/config.ts +1 -1
- package/src/drivers/file-system/actor.ts +20 -2
- package/src/drivers/file-system/global-state.ts +569 -258
- package/src/drivers/file-system/kv-limits.ts +70 -0
- package/src/drivers/file-system/manager.ts +22 -6
- package/src/drivers/file-system/mod.ts +39 -16
- package/src/drivers/file-system/sqlite-runtime.ts +210 -0
- package/src/inspector/actor-inspector.ts +224 -102
- package/src/inspector/config.ts +1 -1
- package/src/inspector/handler.ts +102 -20
- package/src/inspector/mod.browser.ts +8 -0
- package/src/inspector/mod.ts +2 -0
- package/src/inspector/serve-ui.ts +40 -0
- package/src/inspector/transport.ts +18 -0
- package/src/inspector/utils.ts +5 -39
- package/src/manager/gateway.ts +1 -1
- package/src/manager/protocol/mod.ts +1 -1
- package/src/manager/protocol/query.ts +1 -1
- package/src/manager/router-schema.ts +1 -1
- package/src/manager/router.ts +38 -12
- package/src/manager-api/actors.ts +1 -1
- package/src/manager-api/common.ts +1 -1
- package/src/registry/config/driver.ts +1 -1
- package/src/registry/config/index.ts +212 -43
- package/src/registry/config/legacy-runner.ts +1 -1
- package/src/registry/config/runner.ts +1 -1
- package/src/registry/config/serverless.ts +1 -1
- package/src/registry/index.ts +7 -5
- package/src/remote-manager-driver/api-utils.ts +1 -1
- package/src/schemas/actor-inspector/mod.ts +1 -1
- package/src/schemas/actor-inspector/versioned.ts +195 -8
- package/src/schemas/actor-persist/versioned.ts +87 -7
- package/src/schemas/client-protocol/mod.ts +1 -1
- package/src/schemas/client-protocol/versioned.ts +127 -11
- package/src/schemas/client-protocol-zod/mod.ts +16 -1
- package/src/schemas/persist/mod.ts +1 -0
- package/src/schemas/transport/mod.ts +1 -0
- package/src/serde.ts +1 -1
- package/src/serve-test-suite/mod.ts +10 -9
- package/src/test/mod.ts +15 -56
- package/src/utils/endpoint-parser.test.ts +1 -1
- package/src/utils/endpoint-parser.ts +1 -1
- package/src/utils/env-vars.ts +12 -1
- package/src/utils/node.ts +15 -2
- package/src/utils.test.ts +34 -0
- package/src/utils.ts +140 -6
- package/src/workflow/constants.ts +2 -0
- package/src/workflow/context.ts +532 -0
- package/src/workflow/driver.ts +191 -0
- package/src/workflow/inspector.ts +268 -0
- package/src/workflow/mod.ts +122 -0
- package/dist/tsup/chunk-2IJTYN6K.cjs +0 -278
- package/dist/tsup/chunk-2IJTYN6K.cjs.map +0 -1
- package/dist/tsup/chunk-2XQS746M.cjs.map +0 -1
- package/dist/tsup/chunk-3VP5CSHV.cjs +0 -114
- package/dist/tsup/chunk-3VP5CSHV.cjs.map +0 -1
- package/dist/tsup/chunk-AQFSQMBG.js +0 -114
- package/dist/tsup/chunk-AQFSQMBG.js.map +0 -1
- package/dist/tsup/chunk-E6ZE2YEA.js +0 -664
- package/dist/tsup/chunk-E6ZE2YEA.js.map +0 -1
- package/dist/tsup/chunk-FJ3KTN4V.js.map +0 -1
- package/dist/tsup/chunk-GBENOENJ.cjs +0 -8
- package/dist/tsup/chunk-GBENOENJ.cjs.map +0 -1
- package/dist/tsup/chunk-GD7UXGOE.cjs +0 -4762
- package/dist/tsup/chunk-GD7UXGOE.cjs.map +0 -1
- package/dist/tsup/chunk-GMAVRZSF.js.map +0 -1
- package/dist/tsup/chunk-H4TB4X25.cjs.map +0 -1
- package/dist/tsup/chunk-JDAD2YFA.js.map +0 -1
- package/dist/tsup/chunk-KCOVZOPS.js +0 -1946
- package/dist/tsup/chunk-KCOVZOPS.js.map +0 -1
- package/dist/tsup/chunk-KDFWJKMJ.cjs +0 -664
- package/dist/tsup/chunk-KDFWJKMJ.cjs.map +0 -1
- package/dist/tsup/chunk-LFVF5SCU.js.map +0 -1
- package/dist/tsup/chunk-Q6W7RJJP.js.map +0 -1
- package/dist/tsup/chunk-RUW5CZ5Z.cjs +0 -1949
- package/dist/tsup/chunk-RUW5CZ5Z.cjs.map +0 -1
- package/dist/tsup/chunk-RZW2DNND.cjs.map +0 -1
- package/dist/tsup/chunk-TCOEBUUE.js +0 -278
- package/dist/tsup/chunk-TCOEBUUE.js.map +0 -1
- package/dist/tsup/chunk-X35U3YNX.cjs.map +0 -1
- package/dist/tsup/keys-Chhy4ylv.d.cts +0 -8
- package/dist/tsup/keys-Chhy4ylv.d.ts +0 -8
- package/dist/tsup/v1-Gq4avTK3.d.cts +0 -240
- package/dist/tsup/v1-Gq4avTK3.d.ts +0 -240
- /package/dist/tsup/{chunk-XXGJCOL6.js.map → chunk-A6YIZWTK.js.map} +0 -0
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import type { OtlpExportTraceServiceRequestJson } from "@rivetkit/traces";
|
|
2
|
+
import {
|
|
3
|
+
createNoopTraces,
|
|
4
|
+
createTraces,
|
|
5
|
+
type SpanHandle,
|
|
6
|
+
type SpanStatusInput,
|
|
7
|
+
type Traces,
|
|
8
|
+
} from "@rivetkit/traces";
|
|
9
|
+
import type { SqliteVfs } from "@rivetkit/sqlite-vfs";
|
|
1
10
|
import invariant from "invariant";
|
|
2
11
|
import type { ActorKey } from "@/actor/mod";
|
|
3
12
|
import type { Client } from "@/client/client";
|
|
@@ -11,7 +20,11 @@ import {
|
|
|
11
20
|
CONN_VERSIONED,
|
|
12
21
|
} from "@/schemas/actor-persist/versioned";
|
|
13
22
|
import { EXTRA_ERROR_LOG } from "@/utils";
|
|
14
|
-
import
|
|
23
|
+
import { getRivetExperimentalOtel } from "@/utils/env-vars";
|
|
24
|
+
import {
|
|
25
|
+
type ActorConfig,
|
|
26
|
+
getRunFunction,
|
|
27
|
+
} from "../config";
|
|
15
28
|
import type { ConnDriver } from "../conn/driver";
|
|
16
29
|
import { createHttpDriver } from "../conn/drivers/http";
|
|
17
30
|
import {
|
|
@@ -25,17 +38,24 @@ import {
|
|
|
25
38
|
type PersistedConn,
|
|
26
39
|
} from "../conn/persisted";
|
|
27
40
|
import {
|
|
28
|
-
|
|
41
|
+
ActionContext,
|
|
29
42
|
ActorContext,
|
|
30
43
|
RequestContext,
|
|
31
44
|
WebSocketContext,
|
|
32
45
|
} from "../contexts";
|
|
46
|
+
|
|
33
47
|
import type { AnyDatabaseProvider, InferDatabaseClient } from "../database";
|
|
34
48
|
import type { ActorDriver } from "../driver";
|
|
35
49
|
import * as errors from "../errors";
|
|
36
50
|
import { serializeActorKey } from "../keys";
|
|
37
51
|
import { processMessage } from "../protocol/old";
|
|
38
52
|
import { Schedule } from "../schedule";
|
|
53
|
+
import {
|
|
54
|
+
type EventSchemaConfig,
|
|
55
|
+
getEventCanSubscribe,
|
|
56
|
+
getQueueCanPublish,
|
|
57
|
+
type QueueSchemaConfig,
|
|
58
|
+
} from "../schema";
|
|
39
59
|
import {
|
|
40
60
|
assertUnreachable,
|
|
41
61
|
DeadlineError,
|
|
@@ -49,8 +69,10 @@ import {
|
|
|
49
69
|
convertActorFromBarePersisted,
|
|
50
70
|
type PersistedActor,
|
|
51
71
|
} from "./persisted";
|
|
72
|
+
import { QueueManager } from "./queue-manager";
|
|
52
73
|
import { ScheduleManager } from "./schedule-manager";
|
|
53
74
|
import { type SaveStateOptions, StateManager } from "./state-manager";
|
|
75
|
+
import { ActorTracesDriver } from "./traces-driver";
|
|
54
76
|
|
|
55
77
|
export type { SaveStateOptions };
|
|
56
78
|
|
|
@@ -59,47 +81,71 @@ enum CanSleep {
|
|
|
59
81
|
NotReady,
|
|
60
82
|
NotStarted,
|
|
61
83
|
ActiveConns,
|
|
84
|
+
ActiveDisconnectCallbacks,
|
|
62
85
|
ActiveHonoHttpRequests,
|
|
86
|
+
ActiveKeepAwake,
|
|
87
|
+
ActiveRun,
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
/** Actor type alias with all `any` types. Used for `extends` in classes referencing this actor. */
|
|
66
|
-
export type AnyActorInstance = ActorInstance<
|
|
91
|
+
export type AnyActorInstance = ActorInstance<
|
|
92
|
+
any,
|
|
93
|
+
any,
|
|
94
|
+
any,
|
|
95
|
+
any,
|
|
96
|
+
any,
|
|
97
|
+
any,
|
|
98
|
+
any,
|
|
99
|
+
any
|
|
100
|
+
>;
|
|
67
101
|
|
|
68
102
|
export type ExtractActorState<A extends AnyActorInstance> =
|
|
69
|
-
A extends ActorInstance<infer State, any, any, any, any, any>
|
|
103
|
+
A extends ActorInstance<infer State, any, any, any, any, any, any, any>
|
|
70
104
|
? State
|
|
71
105
|
: never;
|
|
72
106
|
|
|
73
107
|
export type ExtractActorConnParams<A extends AnyActorInstance> =
|
|
74
|
-
A extends ActorInstance<any, infer ConnParams, any, any, any, any>
|
|
108
|
+
A extends ActorInstance<any, infer ConnParams, any, any, any, any, any, any>
|
|
75
109
|
? ConnParams
|
|
76
110
|
: never;
|
|
77
111
|
|
|
78
112
|
export type ExtractActorConnState<A extends AnyActorInstance> =
|
|
79
|
-
A extends ActorInstance<any, any, infer ConnState, any, any, any>
|
|
113
|
+
A extends ActorInstance<any, any, infer ConnState, any, any, any, any, any>
|
|
80
114
|
? ConnState
|
|
81
115
|
: never;
|
|
82
116
|
|
|
83
117
|
// MARK: - Main ActorInstance Class
|
|
84
|
-
export class ActorInstance<
|
|
118
|
+
export class ActorInstance<
|
|
119
|
+
S,
|
|
120
|
+
CP,
|
|
121
|
+
CS,
|
|
122
|
+
V,
|
|
123
|
+
I,
|
|
124
|
+
DB extends AnyDatabaseProvider,
|
|
125
|
+
E extends EventSchemaConfig = Record<never, never>,
|
|
126
|
+
Q extends QueueSchemaConfig = Record<never, never>,
|
|
127
|
+
> {
|
|
85
128
|
// MARK: - Core Properties
|
|
86
|
-
actorContext: ActorContext<S, CP, CS, V, I, DB>;
|
|
87
|
-
#config: ActorConfig<S, CP, CS, V, I, DB>;
|
|
129
|
+
actorContext: ActorContext<S, CP, CS, V, I, DB, E, Q>;
|
|
130
|
+
#config: ActorConfig<S, CP, CS, V, I, DB, E, Q>;
|
|
88
131
|
driver!: ActorDriver;
|
|
89
132
|
#inlineClient!: Client<Registry<any>>;
|
|
90
133
|
#actorId!: string;
|
|
91
134
|
#name!: string;
|
|
92
135
|
#key!: ActorKey;
|
|
136
|
+
#actorKeyString!: string;
|
|
93
137
|
#region!: string;
|
|
94
138
|
|
|
95
139
|
// MARK: - Managers
|
|
96
|
-
connectionManager!: ConnectionManager<S, CP, CS, V, I, DB>;
|
|
140
|
+
connectionManager!: ConnectionManager<S, CP, CS, V, I, DB, E, Q>;
|
|
141
|
+
|
|
142
|
+
stateManager!: StateManager<S, CP, CS, I, E, Q>;
|
|
97
143
|
|
|
98
|
-
|
|
144
|
+
eventManager!: EventManager<S, CP, CS, V, I, DB, E, Q>;
|
|
99
145
|
|
|
100
|
-
|
|
146
|
+
#scheduleManager!: ScheduleManager<S, CP, CS, V, I, DB, E, Q>;
|
|
101
147
|
|
|
102
|
-
|
|
148
|
+
queueManager!: QueueManager<S, CP, CS, V, I, DB, E, Q>;
|
|
103
149
|
|
|
104
150
|
// MARK: - Logging
|
|
105
151
|
#log!: Logger;
|
|
@@ -126,25 +172,34 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
126
172
|
|
|
127
173
|
// MARK: - Variables & Database
|
|
128
174
|
#vars?: V;
|
|
129
|
-
#db
|
|
175
|
+
#db?: InferDatabaseClient<DB>;
|
|
176
|
+
#sqliteVfs?: SqliteVfs;
|
|
130
177
|
|
|
131
178
|
// MARK: - Background Tasks
|
|
132
179
|
#backgroundPromises: Promise<void>[] = [];
|
|
180
|
+
#runPromise?: Promise<void>;
|
|
181
|
+
#runHandlerActive = false;
|
|
182
|
+
#activeQueueWaitCount = 0;
|
|
133
183
|
|
|
134
184
|
// MARK: - HTTP/WebSocket Tracking
|
|
135
185
|
#activeHonoHttpRequests = 0;
|
|
186
|
+
#activeKeepAwakeCount = 0;
|
|
136
187
|
|
|
137
188
|
// MARK: - Deprecated (kept for compatibility)
|
|
138
189
|
#schedule!: Schedule;
|
|
139
190
|
|
|
140
191
|
// MARK: - Inspector
|
|
141
192
|
#inspectorToken?: string;
|
|
142
|
-
#inspector
|
|
193
|
+
#inspector: ActorInspector;
|
|
194
|
+
|
|
195
|
+
// MARK: - Tracing
|
|
196
|
+
#traces!: Traces<OtlpExportTraceServiceRequestJson>;
|
|
143
197
|
|
|
144
198
|
// MARK: - Constructor
|
|
145
|
-
constructor(config: ActorConfig<S, CP, CS, V, I, DB>) {
|
|
199
|
+
constructor(config: ActorConfig<S, CP, CS, V, I, DB, E, Q>) {
|
|
146
200
|
this.#config = config;
|
|
147
201
|
this.actorContext = new ActorContext(this);
|
|
202
|
+
this.#inspector = new ActorInspector(this);
|
|
148
203
|
}
|
|
149
204
|
|
|
150
205
|
// MARK: - Public Getters
|
|
@@ -186,11 +241,73 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
186
241
|
return this.#inspector;
|
|
187
242
|
}
|
|
188
243
|
|
|
244
|
+
get traces(): Traces<OtlpExportTraceServiceRequestJson> {
|
|
245
|
+
return this.#traces;
|
|
246
|
+
}
|
|
247
|
+
|
|
189
248
|
get inspectorToken(): string | undefined {
|
|
190
249
|
return this.#inspectorToken;
|
|
191
250
|
}
|
|
192
251
|
|
|
193
|
-
|
|
252
|
+
// MARK: - Tracing
|
|
253
|
+
getCurrentTraceSpan(): SpanHandle | null {
|
|
254
|
+
return this.#traces.getCurrentSpan();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
startTraceSpan(
|
|
258
|
+
name: string,
|
|
259
|
+
attributes?: Record<string, unknown>,
|
|
260
|
+
): SpanHandle {
|
|
261
|
+
return this.#traces.startSpan(name, {
|
|
262
|
+
parent: this.#traces.getCurrentSpan() ?? undefined,
|
|
263
|
+
attributes: this.#traceAttributes(attributes),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
endTraceSpan(handle: SpanHandle, status?: SpanStatusInput): void {
|
|
268
|
+
this.#traces.endSpan(handle, status ? { status } : undefined);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async runInTraceSpan<T>(
|
|
272
|
+
name: string,
|
|
273
|
+
attributes: Record<string, unknown> | undefined,
|
|
274
|
+
fn: () => T | Promise<T>,
|
|
275
|
+
): Promise<T> {
|
|
276
|
+
const span = this.startTraceSpan(name, attributes);
|
|
277
|
+
try {
|
|
278
|
+
const result = this.#traces.withSpan(span, fn);
|
|
279
|
+
const resolved = result instanceof Promise ? await result : result;
|
|
280
|
+
this.#traces.endSpan(span, {
|
|
281
|
+
status: { code: "OK" },
|
|
282
|
+
});
|
|
283
|
+
return resolved;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
this.#traces.endSpan(span, {
|
|
286
|
+
status: {
|
|
287
|
+
code: "ERROR",
|
|
288
|
+
message: stringifyError(error),
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
emitTraceEvent(
|
|
296
|
+
name: string,
|
|
297
|
+
attributes?: Record<string, unknown>,
|
|
298
|
+
handle?: SpanHandle,
|
|
299
|
+
): void {
|
|
300
|
+
const span = handle ?? this.#traces.getCurrentSpan();
|
|
301
|
+
if (!span) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
this.#traces.emitEvent(span, name, {
|
|
305
|
+
attributes: this.#traceAttributes(attributes),
|
|
306
|
+
timeUnixMs: Date.now(),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
get conns(): Map<ConnId, Conn<S, CP, CS, V, I, DB, E, Q>> {
|
|
194
311
|
return this.connectionManager.connections;
|
|
195
312
|
}
|
|
196
313
|
|
|
@@ -206,7 +323,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
206
323
|
return Object.keys(this.#config.actions ?? {});
|
|
207
324
|
}
|
|
208
325
|
|
|
209
|
-
get config(): ActorConfig<S, CP, CS, V, I, DB> {
|
|
326
|
+
get config(): ActorConfig<S, CP, CS, V, I, DB, E, Q> {
|
|
210
327
|
return this.#config;
|
|
211
328
|
}
|
|
212
329
|
|
|
@@ -260,8 +377,12 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
260
377
|
this.#actorId = actorId;
|
|
261
378
|
this.#name = name;
|
|
262
379
|
this.#key = key;
|
|
380
|
+
this.#actorKeyString = serializeActorKey(this.#key);
|
|
263
381
|
this.#region = region;
|
|
264
382
|
|
|
383
|
+
// Initialize tracing
|
|
384
|
+
this.#initializeTraces();
|
|
385
|
+
|
|
265
386
|
// Initialize logging
|
|
266
387
|
this.#initializeLogging();
|
|
267
388
|
|
|
@@ -269,6 +390,7 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
269
390
|
this.connectionManager = new ConnectionManager(this);
|
|
270
391
|
this.stateManager = new StateManager(this, actorDriver, this.#config);
|
|
271
392
|
this.eventManager = new EventManager(this);
|
|
393
|
+
this.queueManager = new QueueManager(this, actorDriver);
|
|
272
394
|
this.#scheduleManager = new ScheduleManager(
|
|
273
395
|
this,
|
|
274
396
|
actorDriver,
|
|
@@ -281,6 +403,8 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
281
403
|
// Load state
|
|
282
404
|
await this.#loadState();
|
|
283
405
|
|
|
406
|
+
await this.queueManager.initialize();
|
|
407
|
+
|
|
284
408
|
// Generate or load inspector token
|
|
285
409
|
await this.#initializeInspectorToken();
|
|
286
410
|
|
|
@@ -318,6 +442,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
318
442
|
// timer
|
|
319
443
|
this.resetSleepTimer();
|
|
320
444
|
|
|
445
|
+
// Start run handler in background (does not block startup)
|
|
446
|
+
this.#startRunHandler();
|
|
447
|
+
|
|
321
448
|
// Trigger any pending alarms
|
|
322
449
|
await this.onAlarm();
|
|
323
450
|
}
|
|
@@ -333,6 +460,13 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
333
460
|
throw new errors.InternalError("Actor is stopping");
|
|
334
461
|
}
|
|
335
462
|
|
|
463
|
+
async cleanupPersistedConnections(reason?: string): Promise<number> {
|
|
464
|
+
this.assertReady(true);
|
|
465
|
+
return await this.connectionManager.cleanupPersistedHibernatableConnections(
|
|
466
|
+
reason,
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
336
470
|
// MARK: - Stop
|
|
337
471
|
async onStop(mode: "sleep" | "destroy") {
|
|
338
472
|
if (this.#stopCalled) {
|
|
@@ -345,46 +479,53 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
345
479
|
mode,
|
|
346
480
|
});
|
|
347
481
|
|
|
348
|
-
// Clear sleep timeout
|
|
349
|
-
if (this.#sleepTimeout) {
|
|
350
|
-
clearTimeout(this.#sleepTimeout);
|
|
351
|
-
this.#sleepTimeout = undefined;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Abort listeners
|
|
355
482
|
try {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
await this.#callOnSleep();
|
|
362
|
-
} else if (mode === "destroy") {
|
|
363
|
-
await this.#callOnDestroy();
|
|
364
|
-
} else {
|
|
365
|
-
assertUnreachable(mode);
|
|
366
|
-
}
|
|
483
|
+
// Clear sleep timeout
|
|
484
|
+
if (this.#sleepTimeout) {
|
|
485
|
+
clearTimeout(this.#sleepTimeout);
|
|
486
|
+
this.#sleepTimeout = undefined;
|
|
487
|
+
}
|
|
367
488
|
|
|
368
|
-
|
|
369
|
-
|
|
489
|
+
// Abort listeners
|
|
490
|
+
try {
|
|
491
|
+
this.#abortController.abort();
|
|
492
|
+
} catch { }
|
|
370
493
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
this.#config.options.waitUntilTimeout,
|
|
374
|
-
);
|
|
494
|
+
// Wait for run handler to complete
|
|
495
|
+
await this.#waitForRunHandler(this.#config.options.runStopTimeout);
|
|
375
496
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
497
|
+
// Call onStop lifecycle
|
|
498
|
+
if (mode === "sleep") {
|
|
499
|
+
await this.#callOnSleep();
|
|
500
|
+
} else if (mode === "destroy") {
|
|
501
|
+
await this.#callOnDestroy();
|
|
502
|
+
} else {
|
|
503
|
+
assertUnreachable(mode);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Disconnect non-hibernatable connections
|
|
507
|
+
await this.#disconnectConnections();
|
|
508
|
+
|
|
509
|
+
// Wait for background tasks
|
|
510
|
+
await this.#waitBackgroundPromises(
|
|
511
|
+
this.#config.options.waitUntilTimeout,
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
// Clear timeouts and save state
|
|
515
|
+
this.#rLog.info({ msg: "clearing pending save timeouts" });
|
|
516
|
+
this.stateManager.clearPendingSaveTimeout();
|
|
517
|
+
this.#rLog.info({ msg: "saving state immediately" });
|
|
518
|
+
await this.stateManager.saveState({
|
|
519
|
+
immediate: true,
|
|
520
|
+
allowStoppingState: true,
|
|
521
|
+
});
|
|
384
522
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
523
|
+
// Wait for write queues
|
|
524
|
+
await this.stateManager.waitForPendingWrites();
|
|
525
|
+
await this.#scheduleManager.waitForPendingAlarmWrites();
|
|
526
|
+
} finally {
|
|
527
|
+
await this.#cleanupDatabase();
|
|
528
|
+
}
|
|
388
529
|
}
|
|
389
530
|
|
|
390
531
|
// MARK: - Sleep
|
|
@@ -468,49 +609,71 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
468
609
|
async processMessage(
|
|
469
610
|
message: {
|
|
470
611
|
body:
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
612
|
+
| {
|
|
613
|
+
tag: "ActionRequest";
|
|
614
|
+
val: { id: bigint; name: string; args: unknown };
|
|
615
|
+
}
|
|
616
|
+
| {
|
|
617
|
+
tag: "SubscriptionRequest";
|
|
618
|
+
val: { eventName: string; subscribe: boolean };
|
|
619
|
+
};
|
|
479
620
|
},
|
|
480
|
-
conn: Conn<S, CP, CS, V, I, DB>,
|
|
621
|
+
conn: Conn<S, CP, CS, V, I, DB, E, Q>,
|
|
481
622
|
) {
|
|
482
623
|
await processMessage(message, this, conn, {
|
|
483
624
|
onExecuteAction: async (ctx, name, args) => {
|
|
484
|
-
this.inspector.emitter.emit("eventFired", {
|
|
485
|
-
type: "action",
|
|
486
|
-
name,
|
|
487
|
-
args,
|
|
488
|
-
connId: conn.id,
|
|
489
|
-
});
|
|
490
625
|
return await this.executeAction(ctx, name, args);
|
|
491
626
|
},
|
|
492
627
|
onSubscribe: async (eventName, conn) => {
|
|
493
|
-
this.inspector.emitter.emit("eventFired", {
|
|
494
|
-
type: "subscribe",
|
|
495
|
-
eventName,
|
|
496
|
-
connId: conn.id,
|
|
497
|
-
});
|
|
498
628
|
this.eventManager.addSubscription(eventName, conn, false);
|
|
499
629
|
},
|
|
500
630
|
onUnsubscribe: async (eventName, conn) => {
|
|
501
|
-
this.inspector.emitter.emit("eventFired", {
|
|
502
|
-
type: "unsubscribe",
|
|
503
|
-
eventName,
|
|
504
|
-
connId: conn.id,
|
|
505
|
-
});
|
|
506
631
|
this.eventManager.removeSubscription(eventName, conn, false);
|
|
507
632
|
},
|
|
508
633
|
});
|
|
509
634
|
}
|
|
510
635
|
|
|
636
|
+
async assertCanSubscribe(
|
|
637
|
+
ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
|
|
638
|
+
eventName: string,
|
|
639
|
+
): Promise<void> {
|
|
640
|
+
const canSubscribe = getEventCanSubscribe(this.#config.events, eventName);
|
|
641
|
+
if (!canSubscribe) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const result = await canSubscribe(ctx);
|
|
646
|
+
if (typeof result !== "boolean") {
|
|
647
|
+
throw new errors.InvalidCanSubscribeResponse();
|
|
648
|
+
}
|
|
649
|
+
if (!result) {
|
|
650
|
+
throw new errors.Forbidden();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
async assertCanPublish(
|
|
655
|
+
ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
|
|
656
|
+
queueName: string,
|
|
657
|
+
): Promise<void> {
|
|
658
|
+
const canPublish = getQueueCanPublish<
|
|
659
|
+
ActionContext<S, CP, CS, V, I, DB, E, Q>
|
|
660
|
+
>(this.#config.queues, queueName);
|
|
661
|
+
if (!canPublish) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const result = await canPublish(ctx);
|
|
666
|
+
if (typeof result !== "boolean") {
|
|
667
|
+
throw new errors.InvalidCanPublishResponse();
|
|
668
|
+
}
|
|
669
|
+
if (!result) {
|
|
670
|
+
throw new errors.Forbidden();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
511
674
|
// MARK: - Action Execution
|
|
512
675
|
async executeAction(
|
|
513
|
-
ctx: ActionContext<S, CP, CS, V, I, DB>,
|
|
676
|
+
ctx: ActionContext<S, CP, CS, V, I, DB, E, Q>,
|
|
514
677
|
actionName: string,
|
|
515
678
|
args: unknown[],
|
|
516
679
|
): Promise<unknown> {
|
|
@@ -532,54 +695,82 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
532
695
|
throw new errors.ActionNotFound(actionName);
|
|
533
696
|
}
|
|
534
697
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
698
|
+
this.#activeKeepAwakeCount++;
|
|
699
|
+
this.resetSleepTimer();
|
|
700
|
+
const actionSpan = this.startTraceSpan(`actor.action.${actionName}`, {
|
|
701
|
+
"rivet.action.name": actionName,
|
|
702
|
+
});
|
|
703
|
+
let spanEnded = false;
|
|
541
704
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
705
|
+
try {
|
|
706
|
+
return await this.#traces.withSpan(actionSpan, async () => {
|
|
707
|
+
this.#rLog.debug({
|
|
708
|
+
msg: "executing action",
|
|
709
|
+
actionName,
|
|
710
|
+
args,
|
|
711
|
+
});
|
|
547
712
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
this.#config.options.actionTimeout,
|
|
713
|
+
const outputOrPromise = actionFunction.call(
|
|
714
|
+
undefined,
|
|
715
|
+
ctx,
|
|
716
|
+
...args,
|
|
553
717
|
);
|
|
554
|
-
} else {
|
|
555
|
-
output = outputOrPromise;
|
|
556
|
-
}
|
|
557
718
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
719
|
+
let output: unknown;
|
|
720
|
+
const maybeThenable = outputOrPromise as {
|
|
721
|
+
then?: (
|
|
722
|
+
onfulfilled?: unknown,
|
|
723
|
+
onrejected?: unknown,
|
|
724
|
+
) => unknown;
|
|
725
|
+
};
|
|
726
|
+
if (maybeThenable && typeof maybeThenable.then === "function") {
|
|
727
|
+
output = await deadline(
|
|
728
|
+
Promise.resolve(outputOrPromise),
|
|
729
|
+
this.#config.options.actionTimeout,
|
|
566
730
|
);
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
731
|
+
} else {
|
|
732
|
+
output = outputOrPromise;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Process through onBeforeActionResponse if configured
|
|
736
|
+
if (this.#config.onBeforeActionResponse) {
|
|
737
|
+
try {
|
|
738
|
+
output = await this.runInTraceSpan(
|
|
739
|
+
"actor.onBeforeActionResponse",
|
|
740
|
+
{ "rivet.action.name": actionName },
|
|
741
|
+
() =>
|
|
742
|
+
this.#config.onBeforeActionResponse!(
|
|
743
|
+
this.actorContext,
|
|
744
|
+
actionName,
|
|
745
|
+
args,
|
|
746
|
+
output,
|
|
747
|
+
),
|
|
748
|
+
);
|
|
749
|
+
} catch (error) {
|
|
750
|
+
this.#rLog.error({
|
|
751
|
+
msg: "error in `onBeforeActionResponse`",
|
|
752
|
+
error: stringifyError(error),
|
|
753
|
+
});
|
|
571
754
|
}
|
|
572
|
-
} catch (error) {
|
|
573
|
-
this.#rLog.error({
|
|
574
|
-
msg: "error in `onBeforeActionResponse`",
|
|
575
|
-
error: stringifyError(error),
|
|
576
|
-
});
|
|
577
755
|
}
|
|
578
|
-
}
|
|
579
756
|
|
|
580
|
-
|
|
757
|
+
return output;
|
|
758
|
+
});
|
|
581
759
|
} catch (error) {
|
|
582
|
-
|
|
760
|
+
const isTimeout = error instanceof DeadlineError;
|
|
761
|
+
const message = isTimeout
|
|
762
|
+
? "ActionTimedOut"
|
|
763
|
+
: stringifyError(error);
|
|
764
|
+
this.#traces.setAttributes(actionSpan, {
|
|
765
|
+
"error.message": message,
|
|
766
|
+
"error.type":
|
|
767
|
+
error instanceof Error ? error.name : typeof error,
|
|
768
|
+
});
|
|
769
|
+
this.#traces.endSpan(actionSpan, {
|
|
770
|
+
status: { code: "ERROR", message },
|
|
771
|
+
});
|
|
772
|
+
spanEnded = true;
|
|
773
|
+
if (isTimeout) {
|
|
583
774
|
throw new errors.ActionTimedOut();
|
|
584
775
|
}
|
|
585
776
|
this.#rLog.error({
|
|
@@ -589,13 +780,27 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
589
780
|
});
|
|
590
781
|
throw error;
|
|
591
782
|
} finally {
|
|
783
|
+
if (!spanEnded && actionSpan.isActive()) {
|
|
784
|
+
this.#traces.endSpan(actionSpan, {
|
|
785
|
+
status: { code: "OK" },
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
this.#activeKeepAwakeCount--;
|
|
789
|
+
if (this.#activeKeepAwakeCount < 0) {
|
|
790
|
+
this.#activeKeepAwakeCount = 0;
|
|
791
|
+
this.#rLog.warn({
|
|
792
|
+
msg: "active keep awake count went below 0, this is a RivetKit bug",
|
|
793
|
+
...EXTRA_ERROR_LOG,
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
this.resetSleepTimer();
|
|
592
797
|
this.stateManager.savePersistThrottled();
|
|
593
798
|
}
|
|
594
799
|
}
|
|
595
800
|
|
|
596
801
|
// MARK: - HTTP/WebSocket Handlers
|
|
597
802
|
async handleRawRequest(
|
|
598
|
-
conn: Conn<S, CP, CS, V, I, DB>,
|
|
803
|
+
conn: Conn<S, CP, CS, V, I, DB, E, Q>,
|
|
599
804
|
request: Request,
|
|
600
805
|
): Promise<Response> {
|
|
601
806
|
this.assertReady();
|
|
@@ -603,27 +808,38 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
603
808
|
if (!this.#config.onRequest) {
|
|
604
809
|
throw new errors.RequestHandlerNotDefined();
|
|
605
810
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
811
|
+
const onRequest = this.#config.onRequest;
|
|
812
|
+
|
|
813
|
+
return await this.runInTraceSpan(
|
|
814
|
+
"actor.onRequest",
|
|
815
|
+
{
|
|
816
|
+
"http.method": request.method,
|
|
817
|
+
"http.url": request.url,
|
|
818
|
+
"rivet.conn.id": conn.id,
|
|
819
|
+
},
|
|
820
|
+
async () => {
|
|
821
|
+
const ctx = new RequestContext(this, conn, request);
|
|
822
|
+
try {
|
|
823
|
+
const response = await onRequest(ctx, request);
|
|
824
|
+
if (!response) {
|
|
825
|
+
throw new errors.InvalidRequestHandlerResponse();
|
|
826
|
+
}
|
|
827
|
+
return response;
|
|
828
|
+
} catch (error) {
|
|
829
|
+
this.#rLog.error({
|
|
830
|
+
msg: "onRequest error",
|
|
831
|
+
error: stringifyError(error),
|
|
832
|
+
});
|
|
833
|
+
throw error;
|
|
834
|
+
} finally {
|
|
835
|
+
this.stateManager.savePersistThrottled();
|
|
836
|
+
}
|
|
837
|
+
},
|
|
838
|
+
);
|
|
622
839
|
}
|
|
623
|
-
}
|
|
624
840
|
|
|
625
841
|
handleRawWebSocket(
|
|
626
|
-
conn: Conn<S, CP, CS, V, I, DB>,
|
|
842
|
+
conn: Conn<S, CP, CS, V, I, DB, E, Q>,
|
|
627
843
|
websocket: UniversalWebSocket,
|
|
628
844
|
request?: Request,
|
|
629
845
|
) {
|
|
@@ -635,6 +851,12 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
635
851
|
throw new errors.InternalError("onWebSocket handler not defined");
|
|
636
852
|
}
|
|
637
853
|
|
|
854
|
+
const span = this.startTraceSpan("actor.onWebSocket", {
|
|
855
|
+
"http.url": request?.url,
|
|
856
|
+
"rivet.conn.id": conn.id,
|
|
857
|
+
});
|
|
858
|
+
let spanEnded = false;
|
|
859
|
+
|
|
638
860
|
try {
|
|
639
861
|
// Reset sleep timer when handling WebSocket
|
|
640
862
|
this.resetSleepTimer();
|
|
@@ -643,17 +865,50 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
643
865
|
const ctx = new WebSocketContext(this, conn, request);
|
|
644
866
|
|
|
645
867
|
// NOTE: This is async and will run in the background
|
|
646
|
-
const voidOrPromise = this.#
|
|
868
|
+
const voidOrPromise = this.#traces.withSpan(span, () =>
|
|
869
|
+
this.#config.onWebSocket!(ctx, websocket),
|
|
870
|
+
);
|
|
647
871
|
|
|
648
872
|
// Save changes from the WebSocket open
|
|
649
873
|
if (voidOrPromise instanceof Promise) {
|
|
650
|
-
voidOrPromise
|
|
651
|
-
|
|
652
|
-
|
|
874
|
+
voidOrPromise
|
|
875
|
+
.then(() => {
|
|
876
|
+
if (!spanEnded) {
|
|
877
|
+
this.endTraceSpan(span, { code: "OK" });
|
|
878
|
+
spanEnded = true;
|
|
879
|
+
}
|
|
880
|
+
})
|
|
881
|
+
.catch((error) => {
|
|
882
|
+
if (!spanEnded) {
|
|
883
|
+
this.endTraceSpan(span, {
|
|
884
|
+
code: "ERROR",
|
|
885
|
+
message: stringifyError(error),
|
|
886
|
+
});
|
|
887
|
+
spanEnded = true;
|
|
888
|
+
}
|
|
889
|
+
this.#rLog.error({
|
|
890
|
+
msg: "onWebSocket error",
|
|
891
|
+
error: stringifyError(error),
|
|
892
|
+
});
|
|
893
|
+
})
|
|
894
|
+
.finally(() => {
|
|
895
|
+
this.stateManager.savePersistThrottled();
|
|
896
|
+
});
|
|
653
897
|
} else {
|
|
898
|
+
if (!spanEnded) {
|
|
899
|
+
this.endTraceSpan(span, { code: "OK" });
|
|
900
|
+
spanEnded = true;
|
|
901
|
+
}
|
|
654
902
|
this.stateManager.savePersistThrottled();
|
|
655
903
|
}
|
|
656
904
|
} catch (error) {
|
|
905
|
+
if (!spanEnded) {
|
|
906
|
+
this.endTraceSpan(span, {
|
|
907
|
+
code: "ERROR",
|
|
908
|
+
message: stringifyError(error),
|
|
909
|
+
});
|
|
910
|
+
spanEnded = true;
|
|
911
|
+
}
|
|
657
912
|
this.#rLog.error({
|
|
658
913
|
msg: "onWebSocket error",
|
|
659
914
|
error: stringifyError(error),
|
|
@@ -693,11 +948,135 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
693
948
|
this.#backgroundPromises.push(nonfailablePromise);
|
|
694
949
|
}
|
|
695
950
|
|
|
951
|
+
/**
|
|
952
|
+
* Prevents the actor from sleeping while the given promise is running.
|
|
953
|
+
*
|
|
954
|
+
* Use this when performing async operations in the `run` handler or other
|
|
955
|
+
* background contexts where you need to ensure the actor stays awake.
|
|
956
|
+
*
|
|
957
|
+
* Returns the resolved value and resets the sleep timer on completion.
|
|
958
|
+
* Errors are propagated to the caller.
|
|
959
|
+
*/
|
|
960
|
+
async keepAwake<T>(promise: Promise<T>): Promise<T> {
|
|
961
|
+
this.assertReady();
|
|
962
|
+
|
|
963
|
+
this.#activeKeepAwakeCount++;
|
|
964
|
+
this.resetSleepTimer();
|
|
965
|
+
|
|
966
|
+
try {
|
|
967
|
+
return await promise;
|
|
968
|
+
} finally {
|
|
969
|
+
this.#activeKeepAwakeCount--;
|
|
970
|
+
if (this.#activeKeepAwakeCount < 0) {
|
|
971
|
+
this.#activeKeepAwakeCount = 0;
|
|
972
|
+
this.#rLog.warn({
|
|
973
|
+
msg: "active keep awake count went below 0, this is a RivetKit bug",
|
|
974
|
+
...EXTRA_ERROR_LOG,
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
this.resetSleepTimer();
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
beginQueueWait() {
|
|
982
|
+
this.assertReady(true);
|
|
983
|
+
this.#activeQueueWaitCount++;
|
|
984
|
+
this.resetSleepTimer();
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
endQueueWait() {
|
|
988
|
+
this.#activeQueueWaitCount--;
|
|
989
|
+
if (this.#activeQueueWaitCount < 0) {
|
|
990
|
+
this.#activeQueueWaitCount = 0;
|
|
991
|
+
this.#rLog.warn({
|
|
992
|
+
msg: "active queue wait count went below 0, this is a RivetKit bug",
|
|
993
|
+
...EXTRA_ERROR_LOG,
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
this.resetSleepTimer();
|
|
997
|
+
}
|
|
998
|
+
|
|
696
999
|
// MARK: - Private Helper Methods
|
|
1000
|
+
#initializeTraces() {
|
|
1001
|
+
if (getRivetExperimentalOtel()) {
|
|
1002
|
+
// Experimental mode persists trace data to actor storage so inspector
|
|
1003
|
+
// queries can return OTel payloads.
|
|
1004
|
+
this.#traces = createTraces({
|
|
1005
|
+
driver: new ActorTracesDriver(this.driver, this.#actorId),
|
|
1006
|
+
});
|
|
1007
|
+
} else {
|
|
1008
|
+
// Keep the tracing API calls active while disabling trace persistence
|
|
1009
|
+
// until the experimental flag is enabled.
|
|
1010
|
+
this.#traces = createNoopTraces();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
#traceAttributes(
|
|
1015
|
+
attributes?: Record<string, unknown>,
|
|
1016
|
+
): Record<string, unknown> {
|
|
1017
|
+
return {
|
|
1018
|
+
"rivet.actor.id": this.#actorId,
|
|
1019
|
+
"rivet.actor.name": this.#name,
|
|
1020
|
+
"rivet.actor.key": this.#actorKeyString,
|
|
1021
|
+
"rivet.actor.region": this.#region,
|
|
1022
|
+
...(attributes ?? {}),
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
#patchLoggerForTraces(logger: Logger) {
|
|
1027
|
+
const levels: Array<
|
|
1028
|
+
"trace" | "debug" | "info" | "warn" | "error" | "fatal"
|
|
1029
|
+
> = ["trace", "debug", "info", "warn", "error", "fatal"];
|
|
1030
|
+
for (const level of levels) {
|
|
1031
|
+
const original = logger[level].bind(logger) as (
|
|
1032
|
+
...args: any[]
|
|
1033
|
+
) => unknown;
|
|
1034
|
+
logger[level] = ((...args: unknown[]) => {
|
|
1035
|
+
this.#emitLogEvent(level, args);
|
|
1036
|
+
return original(...(args as any[]));
|
|
1037
|
+
}) as Logger[typeof level];
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
#emitLogEvent(level: string, args: unknown[]) {
|
|
1042
|
+
const span = this.#traces.getCurrentSpan();
|
|
1043
|
+
if (!span || !span.isActive()) {
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
let message: string | undefined;
|
|
1048
|
+
if (args.length >= 2) {
|
|
1049
|
+
message = String(args[1]);
|
|
1050
|
+
} else if (args.length === 1) {
|
|
1051
|
+
const [value] = args;
|
|
1052
|
+
if (typeof value === "string") {
|
|
1053
|
+
message = value;
|
|
1054
|
+
} else if (
|
|
1055
|
+
typeof value === "number" ||
|
|
1056
|
+
typeof value === "boolean"
|
|
1057
|
+
) {
|
|
1058
|
+
message = String(value);
|
|
1059
|
+
} else if (value && typeof value === "object") {
|
|
1060
|
+
const maybeMsg = (value as { msg?: unknown }).msg;
|
|
1061
|
+
if (maybeMsg !== undefined) {
|
|
1062
|
+
message = String(maybeMsg);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
this.#traces.emitEvent(span, "log", {
|
|
1068
|
+
attributes: this.#traceAttributes({
|
|
1069
|
+
"log.level": level,
|
|
1070
|
+
...(message ? { "log.message": message } : {}),
|
|
1071
|
+
}),
|
|
1072
|
+
timeUnixMs: Date.now(),
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
|
|
697
1076
|
#initializeLogging() {
|
|
698
1077
|
const logParams = {
|
|
699
1078
|
actor: this.#name,
|
|
700
|
-
key:
|
|
1079
|
+
key: this.#actorKeyString,
|
|
701
1080
|
actorId: this.#actorId,
|
|
702
1081
|
};
|
|
703
1082
|
|
|
@@ -716,6 +1095,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
716
1095
|
logParams,
|
|
717
1096
|
),
|
|
718
1097
|
);
|
|
1098
|
+
|
|
1099
|
+
this.#patchLoggerForTraces(this.#log);
|
|
1100
|
+
this.#patchLoggerForTraces(this.#rLog);
|
|
719
1101
|
}
|
|
720
1102
|
|
|
721
1103
|
async #loadState() {
|
|
@@ -753,9 +1135,9 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
753
1135
|
|
|
754
1136
|
// Call onCreate lifecycle
|
|
755
1137
|
if (this.#config.onCreate) {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
persistData.input
|
|
1138
|
+
const onCreate = this.#config.onCreate;
|
|
1139
|
+
await this.runInTraceSpan("actor.onCreate", undefined, () =>
|
|
1140
|
+
onCreate(this.actorContext as any, persistData.input!),
|
|
759
1141
|
);
|
|
760
1142
|
}
|
|
761
1143
|
}
|
|
@@ -821,18 +1203,24 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
821
1203
|
async #initializeVars() {
|
|
822
1204
|
let vars: V | undefined;
|
|
823
1205
|
if ("createVars" in this.#config) {
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
1206
|
+
const createVars = this.#config.createVars;
|
|
1207
|
+
vars = await this.runInTraceSpan(
|
|
1208
|
+
"actor.createVars",
|
|
1209
|
+
undefined,
|
|
1210
|
+
() => {
|
|
1211
|
+
const dataOrPromise = createVars!(
|
|
1212
|
+
this.actorContext as any,
|
|
1213
|
+
this.driver.getContext(this.#actorId),
|
|
1214
|
+
);
|
|
1215
|
+
if (dataOrPromise instanceof Promise) {
|
|
1216
|
+
return deadline(
|
|
1217
|
+
dataOrPromise,
|
|
1218
|
+
this.#config.options.createVarsTimeout,
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
return dataOrPromise;
|
|
1222
|
+
},
|
|
827
1223
|
);
|
|
828
|
-
if (dataOrPromise instanceof Promise) {
|
|
829
|
-
vars = await deadline(
|
|
830
|
-
dataOrPromise,
|
|
831
|
-
this.#config.options.createVarsTimeout,
|
|
832
|
-
);
|
|
833
|
-
} else {
|
|
834
|
-
vars = dataOrPromise;
|
|
835
|
-
}
|
|
836
1224
|
} else if ("vars" in this.#config) {
|
|
837
1225
|
vars = structuredClone(this.#config.vars);
|
|
838
1226
|
} else {
|
|
@@ -846,21 +1234,31 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
846
1234
|
async #callOnStart() {
|
|
847
1235
|
this.#rLog.info({ msg: "actor starting" });
|
|
848
1236
|
if (this.#config.onWake) {
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1237
|
+
const onWake = this.#config.onWake;
|
|
1238
|
+
await this.runInTraceSpan("actor.onWake", undefined, () =>
|
|
1239
|
+
onWake(this.actorContext),
|
|
1240
|
+
);
|
|
853
1241
|
}
|
|
854
1242
|
}
|
|
855
1243
|
|
|
856
1244
|
async #callOnSleep() {
|
|
857
1245
|
if (this.#config.onSleep) {
|
|
1246
|
+
const onSleep = this.#config.onSleep;
|
|
858
1247
|
try {
|
|
859
1248
|
this.#rLog.debug({ msg: "calling onSleep" });
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1249
|
+
await this.runInTraceSpan(
|
|
1250
|
+
"actor.onSleep",
|
|
1251
|
+
undefined,
|
|
1252
|
+
async () => {
|
|
1253
|
+
const result = onSleep(this.actorContext);
|
|
1254
|
+
if (result instanceof Promise) {
|
|
1255
|
+
await deadline(
|
|
1256
|
+
result,
|
|
1257
|
+
this.#config.options.onSleepTimeout,
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
},
|
|
1261
|
+
);
|
|
864
1262
|
this.#rLog.debug({ msg: "onSleep completed" });
|
|
865
1263
|
} catch (error) {
|
|
866
1264
|
if (error instanceof DeadlineError) {
|
|
@@ -877,15 +1275,22 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
877
1275
|
|
|
878
1276
|
async #callOnDestroy() {
|
|
879
1277
|
if (this.#config.onDestroy) {
|
|
1278
|
+
const onDestroy = this.#config.onDestroy;
|
|
880
1279
|
try {
|
|
881
1280
|
this.#rLog.debug({ msg: "calling onDestroy" });
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
this
|
|
887
|
-
|
|
888
|
-
|
|
1281
|
+
await this.runInTraceSpan(
|
|
1282
|
+
"actor.onDestroy",
|
|
1283
|
+
undefined,
|
|
1284
|
+
async () => {
|
|
1285
|
+
const result = onDestroy(this.actorContext);
|
|
1286
|
+
if (result instanceof Promise) {
|
|
1287
|
+
await deadline(
|
|
1288
|
+
result,
|
|
1289
|
+
this.#config.options.onDestroyTimeout,
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
},
|
|
1293
|
+
);
|
|
889
1294
|
this.#rLog.debug({ msg: "onDestroy completed" });
|
|
890
1295
|
} catch (error) {
|
|
891
1296
|
if (error instanceof DeadlineError) {
|
|
@@ -900,15 +1305,212 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
900
1305
|
}
|
|
901
1306
|
}
|
|
902
1307
|
|
|
1308
|
+
#startRunHandler() {
|
|
1309
|
+
const runFn = getRunFunction(this.#config.run);
|
|
1310
|
+
if (!runFn) return;
|
|
1311
|
+
|
|
1312
|
+
this.#rLog.debug({ msg: "starting run handler" });
|
|
1313
|
+
this.#runHandlerActive = true;
|
|
1314
|
+
this.resetSleepTimer();
|
|
1315
|
+
|
|
1316
|
+
const runSpan = this.startTraceSpan("actor.run");
|
|
1317
|
+
const runResult = this.#traces.withSpan(runSpan, () =>
|
|
1318
|
+
runFn(this.actorContext),
|
|
1319
|
+
);
|
|
1320
|
+
|
|
1321
|
+
if (runResult instanceof Promise) {
|
|
1322
|
+
this.#runPromise = runResult
|
|
1323
|
+
.then(() => {
|
|
1324
|
+
if (this.#stopCalled) {
|
|
1325
|
+
if (runSpan.isActive()) {
|
|
1326
|
+
this.endTraceSpan(runSpan, { code: "OK" });
|
|
1327
|
+
}
|
|
1328
|
+
this.#rLog.debug({
|
|
1329
|
+
msg: "run handler exited during actor stop",
|
|
1330
|
+
});
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Run handler exited normally - this should crash the actor
|
|
1335
|
+
this.emitTraceEvent(
|
|
1336
|
+
"actor.crash",
|
|
1337
|
+
{ "rivet.actor.reason": "run_exited" },
|
|
1338
|
+
runSpan,
|
|
1339
|
+
);
|
|
1340
|
+
this.endTraceSpan(runSpan, {
|
|
1341
|
+
code: "ERROR",
|
|
1342
|
+
message: "run exited unexpectedly",
|
|
1343
|
+
});
|
|
1344
|
+
this.#rLog.warn({
|
|
1345
|
+
msg: "run handler exited unexpectedly, crashing actor to reschedule",
|
|
1346
|
+
});
|
|
1347
|
+
this.startDestroy();
|
|
1348
|
+
})
|
|
1349
|
+
.catch((error) => {
|
|
1350
|
+
if (this.#stopCalled) {
|
|
1351
|
+
if (runSpan.isActive()) {
|
|
1352
|
+
this.endTraceSpan(runSpan, { code: "OK" });
|
|
1353
|
+
}
|
|
1354
|
+
this.#rLog.debug({
|
|
1355
|
+
msg: "run handler threw during actor stop",
|
|
1356
|
+
error: stringifyError(error),
|
|
1357
|
+
});
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// Run handler threw an error - crash the actor
|
|
1362
|
+
this.emitTraceEvent(
|
|
1363
|
+
"actor.crash",
|
|
1364
|
+
{
|
|
1365
|
+
"rivet.actor.reason": "run_error",
|
|
1366
|
+
"error.message": stringifyError(error),
|
|
1367
|
+
},
|
|
1368
|
+
runSpan,
|
|
1369
|
+
);
|
|
1370
|
+
this.endTraceSpan(runSpan, {
|
|
1371
|
+
code: "ERROR",
|
|
1372
|
+
message: stringifyError(error),
|
|
1373
|
+
});
|
|
1374
|
+
this.#rLog.error({
|
|
1375
|
+
msg: "run handler threw error, crashing actor to reschedule",
|
|
1376
|
+
error: stringifyError(error),
|
|
1377
|
+
});
|
|
1378
|
+
this.startDestroy();
|
|
1379
|
+
})
|
|
1380
|
+
.finally(() => {
|
|
1381
|
+
this.#runHandlerActive = false;
|
|
1382
|
+
this.resetSleepTimer();
|
|
1383
|
+
});
|
|
1384
|
+
} else if (runSpan.isActive()) {
|
|
1385
|
+
this.endTraceSpan(runSpan, { code: "OK" });
|
|
1386
|
+
this.#runHandlerActive = false;
|
|
1387
|
+
this.resetSleepTimer();
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
async #waitForRunHandler(timeoutMs: number) {
|
|
1392
|
+
if (!this.#runPromise) {
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
this.#rLog.debug({ msg: "waiting for run handler to complete" });
|
|
1397
|
+
|
|
1398
|
+
const timedOut = await Promise.race([
|
|
1399
|
+
this.#runPromise.then(() => false).catch(() => false),
|
|
1400
|
+
new Promise<true>((resolve) =>
|
|
1401
|
+
setTimeout(() => resolve(true), timeoutMs),
|
|
1402
|
+
),
|
|
1403
|
+
]);
|
|
1404
|
+
|
|
1405
|
+
if (timedOut) {
|
|
1406
|
+
this.#rLog.warn({
|
|
1407
|
+
msg: "run handler did not complete in time, it may have leaked - ensure you use c.aborted (or the abort signal c.abortSignal) to exit gracefully",
|
|
1408
|
+
timeoutMs,
|
|
1409
|
+
});
|
|
1410
|
+
} else {
|
|
1411
|
+
this.#rLog.debug({ msg: "run handler completed" });
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
|
|
903
1415
|
async #setupDatabase() {
|
|
904
|
-
if ("db" in this.#config
|
|
905
|
-
|
|
906
|
-
|
|
1416
|
+
if (!("db" in this.#config) || !this.#config.db) {
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
let client: InferDatabaseClient<DB> | undefined;
|
|
1421
|
+
try {
|
|
1422
|
+
// Every actor gets its own SqliteVfs/@rivetkit/sqlite instance. The async
|
|
1423
|
+
// @rivetkit/sqlite build is not re-entrant, and sharing one instance across
|
|
1424
|
+
// actors can cause cross-actor contention and runtime corruption.
|
|
1425
|
+
if (!this.#sqliteVfs && this.driver.createSqliteVfs) {
|
|
1426
|
+
this.#sqliteVfs = await this.driver.createSqliteVfs();
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
client = await this.#config.db.createClient({
|
|
1430
|
+
actorId: this.#actorId,
|
|
1431
|
+
overrideRawDatabaseClient: this.driver.overrideRawDatabaseClient
|
|
1432
|
+
? () => this.driver.overrideRawDatabaseClient!(this.#actorId)
|
|
1433
|
+
: undefined,
|
|
1434
|
+
overrideDrizzleDatabaseClient: this.driver.overrideDrizzleDatabaseClient
|
|
1435
|
+
? () => this.driver.overrideDrizzleDatabaseClient!(this.#actorId)
|
|
1436
|
+
: undefined,
|
|
1437
|
+
kv: {
|
|
1438
|
+
batchPut: (entries) => this.driver.kvBatchPut(this.#actorId, entries),
|
|
1439
|
+
batchGet: (keys) => this.driver.kvBatchGet(this.#actorId, keys),
|
|
1440
|
+
batchDelete: (keys) => this.driver.kvBatchDelete(this.#actorId, keys),
|
|
1441
|
+
},
|
|
1442
|
+
sqliteVfs: this.#sqliteVfs,
|
|
907
1443
|
});
|
|
908
1444
|
this.#rLog.info({ msg: "database migration starting" });
|
|
909
1445
|
await this.#config.db.onMigrate?.(client);
|
|
910
1446
|
this.#rLog.info({ msg: "database migration complete" });
|
|
911
1447
|
this.#db = client;
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
if (client) {
|
|
1450
|
+
try {
|
|
1451
|
+
await this.#config.db.onDestroy?.(client);
|
|
1452
|
+
} catch (cleanupError) {
|
|
1453
|
+
this.#rLog.error({
|
|
1454
|
+
msg: "database setup cleanup failed",
|
|
1455
|
+
error: stringifyError(cleanupError),
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
if (this.#sqliteVfs) {
|
|
1460
|
+
try {
|
|
1461
|
+
await this.#sqliteVfs.destroy();
|
|
1462
|
+
} catch (cleanupError) {
|
|
1463
|
+
this.#rLog.error({
|
|
1464
|
+
msg: "sqlite vfs teardown after setup failure failed",
|
|
1465
|
+
error: stringifyError(cleanupError),
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
this.#sqliteVfs = undefined;
|
|
1470
|
+
if (error instanceof Error) {
|
|
1471
|
+
this.#rLog.error({
|
|
1472
|
+
msg: "database setup failed",
|
|
1473
|
+
error: stringifyError(error),
|
|
1474
|
+
});
|
|
1475
|
+
throw error;
|
|
1476
|
+
}
|
|
1477
|
+
const wrappedError = new Error(`Database setup failed: ${String(error)}`);
|
|
1478
|
+
this.#rLog.error({
|
|
1479
|
+
msg: "database setup failed with non-Error object",
|
|
1480
|
+
error: String(error),
|
|
1481
|
+
errorType: typeof error,
|
|
1482
|
+
});
|
|
1483
|
+
throw wrappedError;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
async #cleanupDatabase() {
|
|
1488
|
+
const client = this.#db;
|
|
1489
|
+
const sqliteVfs = this.#sqliteVfs;
|
|
1490
|
+
const dbConfig = "db" in this.#config ? this.#config.db : undefined;
|
|
1491
|
+
this.#db = undefined;
|
|
1492
|
+
this.#sqliteVfs = undefined;
|
|
1493
|
+
|
|
1494
|
+
if (client && dbConfig) {
|
|
1495
|
+
try {
|
|
1496
|
+
await dbConfig.onDestroy?.(client);
|
|
1497
|
+
} catch (error) {
|
|
1498
|
+
this.#rLog.error({
|
|
1499
|
+
msg: "database cleanup failed",
|
|
1500
|
+
error: stringifyError(error),
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
if (sqliteVfs) {
|
|
1506
|
+
try {
|
|
1507
|
+
await sqliteVfs.destroy();
|
|
1508
|
+
} catch (error) {
|
|
1509
|
+
this.#rLog.error({
|
|
1510
|
+
msg: "sqlite vfs cleanup failed",
|
|
1511
|
+
error: stringifyError(error),
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
912
1514
|
}
|
|
913
1515
|
}
|
|
914
1516
|
|
|
@@ -1010,6 +1612,10 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1010
1612
|
if (!this.#started) return CanSleep.NotReady;
|
|
1011
1613
|
if (this.#activeHonoHttpRequests > 0)
|
|
1012
1614
|
return CanSleep.ActiveHonoHttpRequests;
|
|
1615
|
+
if (this.#activeKeepAwakeCount > 0) return CanSleep.ActiveKeepAwake;
|
|
1616
|
+
if (this.#runHandlerActive && this.#activeQueueWaitCount === 0) {
|
|
1617
|
+
return CanSleep.ActiveRun;
|
|
1618
|
+
}
|
|
1013
1619
|
|
|
1014
1620
|
for (const _conn of this.connectionManager.connections.values()) {
|
|
1015
1621
|
// TODO: Add back
|
|
@@ -1018,6 +1624,10 @@ export class ActorInstance<S, CP, CS, V, I, DB extends AnyDatabaseProvider> {
|
|
|
1018
1624
|
// }
|
|
1019
1625
|
}
|
|
1020
1626
|
|
|
1627
|
+
if (this.connectionManager.pendingDisconnectCount > 0) {
|
|
1628
|
+
return CanSleep.ActiveDisconnectCallbacks;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1021
1631
|
return CanSleep.Yes;
|
|
1022
1632
|
}
|
|
1023
1633
|
|