@adonis-agora/durable 0.1.0
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/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/assets/dashboard.html +446 -0
- package/dist/commands/main.d.ts +15 -0
- package/dist/commands/main.d.ts.map +1 -0
- package/dist/commands/main.js +15 -0
- package/dist/commands/main.js.map +1 -0
- package/dist/commands/retry.d.ts +16 -0
- package/dist/commands/retry.d.ts.map +1 -0
- package/dist/commands/retry.js +34 -0
- package/dist/commands/retry.js.map +1 -0
- package/dist/commands/runs.d.ts +17 -0
- package/dist/commands/runs.d.ts.map +1 -0
- package/dist/commands/runs.js +40 -0
- package/dist/commands/runs.js.map +1 -0
- package/dist/commands/work.d.ts +18 -0
- package/dist/commands/work.d.ts.map +1 -0
- package/dist/commands/work.js +58 -0
- package/dist/commands/work.js.map +1 -0
- package/dist/configure.d.ts +15 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +26 -0
- package/dist/configure.js.map +1 -0
- package/dist/providers/dashboard_provider.d.ts +27 -0
- package/dist/providers/dashboard_provider.d.ts.map +1 -0
- package/dist/providers/dashboard_provider.js +94 -0
- package/dist/providers/dashboard_provider.js.map +1 -0
- package/dist/providers/durable_provider.d.ts +36 -0
- package/dist/providers/durable_provider.d.ts.map +1 -0
- package/dist/providers/durable_provider.js +113 -0
- package/dist/providers/durable_provider.js.map +1 -0
- package/dist/src/admission-redis/index.d.ts +2 -0
- package/dist/src/admission-redis/index.d.ts.map +1 -0
- package/dist/src/admission-redis/index.js +2 -0
- package/dist/src/admission-redis/index.js.map +1 -0
- package/dist/src/admission-redis/redis-admission-backend.d.ts +83 -0
- package/dist/src/admission-redis/redis-admission-backend.d.ts.map +1 -0
- package/dist/src/admission-redis/redis-admission-backend.js +200 -0
- package/dist/src/admission-redis/redis-admission-backend.js.map +1 -0
- package/dist/src/admission.d.ts +49 -0
- package/dist/src/admission.d.ts.map +1 -0
- package/dist/src/admission.js +30 -0
- package/dist/src/admission.js.map +1 -0
- package/dist/src/backoff.d.ts +5 -0
- package/dist/src/backoff.d.ts.map +1 -0
- package/dist/src/backoff.js +11 -0
- package/dist/src/backoff.js.map +1 -0
- package/dist/src/checkpoints.d.ts +42 -0
- package/dist/src/checkpoints.d.ts.map +1 -0
- package/dist/src/checkpoints.js +57 -0
- package/dist/src/checkpoints.js.map +1 -0
- package/dist/src/codec-state-store.d.ts +60 -0
- package/dist/src/codec-state-store.d.ts.map +1 -0
- package/dist/src/codec-state-store.js +129 -0
- package/dist/src/codec-state-store.js.map +1 -0
- package/dist/src/commands/index.d.ts +3 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +3 -0
- package/dist/src/commands/index.js.map +1 -0
- package/dist/src/commands/runs.d.ts +24 -0
- package/dist/src/commands/runs.d.ts.map +1 -0
- package/dist/src/commands/runs.js +39 -0
- package/dist/src/commands/runs.js.map +1 -0
- package/dist/src/commands/worker.d.ts +61 -0
- package/dist/src/commands/worker.d.ts.map +1 -0
- package/dist/src/commands/worker.js +74 -0
- package/dist/src/commands/worker.js.map +1 -0
- package/dist/src/completion.d.ts +15 -0
- package/dist/src/completion.d.ts.map +1 -0
- package/dist/src/completion.js +10 -0
- package/dist/src/completion.js.map +1 -0
- package/dist/src/dashboard/define_config.d.ts +48 -0
- package/dist/src/dashboard/define_config.d.ts.map +1 -0
- package/dist/src/dashboard/define_config.js +57 -0
- package/dist/src/dashboard/define_config.js.map +1 -0
- package/dist/src/dashboard/handlers.d.ts +47 -0
- package/dist/src/dashboard/handlers.d.ts.map +1 -0
- package/dist/src/dashboard/handlers.js +163 -0
- package/dist/src/dashboard/handlers.js.map +1 -0
- package/dist/src/dashboard/html.d.ts +7 -0
- package/dist/src/dashboard/html.d.ts.map +1 -0
- package/dist/src/dashboard/html.js +24 -0
- package/dist/src/dashboard/html.js.map +1 -0
- package/dist/src/dashboard/index.d.ts +8 -0
- package/dist/src/dashboard/index.d.ts.map +1 -0
- package/dist/src/dashboard/index.js +6 -0
- package/dist/src/dashboard/index.js.map +1 -0
- package/dist/src/define_config.d.ts +72 -0
- package/dist/src/define_config.d.ts.map +1 -0
- package/dist/src/define_config.js +8 -0
- package/dist/src/define_config.js.map +1 -0
- package/dist/src/diagnostics-bridge.d.ts +22 -0
- package/dist/src/diagnostics-bridge.d.ts.map +1 -0
- package/dist/src/diagnostics-bridge.js +25 -0
- package/dist/src/diagnostics-bridge.js.map +1 -0
- package/dist/src/duration.d.ts +6 -0
- package/dist/src/duration.d.ts.map +1 -0
- package/dist/src/duration.js +39 -0
- package/dist/src/duration.js.map +1 -0
- package/dist/src/engine.d.ts +583 -0
- package/dist/src/engine.d.ts.map +1 -0
- package/dist/src/engine.js +1894 -0
- package/dist/src/engine.js.map +1 -0
- package/dist/src/entities.d.ts +44 -0
- package/dist/src/entities.d.ts.map +1 -0
- package/dist/src/entities.js +64 -0
- package/dist/src/entities.js.map +1 -0
- package/dist/src/errors.d.ts +68 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +102 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/event-accumulators.d.ts +39 -0
- package/dist/src/event-accumulators.d.ts.map +1 -0
- package/dist/src/event-accumulators.js +70 -0
- package/dist/src/event-accumulators.js.map +1 -0
- package/dist/src/events.d.ts +9 -0
- package/dist/src/events.d.ts.map +1 -0
- package/dist/src/events.js +35 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/index.d.ts +36 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +37 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interfaces.d.ts +909 -0
- package/dist/src/interfaces.d.ts.map +1 -0
- package/dist/src/interfaces.js +2 -0
- package/dist/src/interfaces.js.map +1 -0
- package/dist/src/metrics.d.ts +44 -0
- package/dist/src/metrics.d.ts.map +1 -0
- package/dist/src/metrics.js +78 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/otel/durable-metrics.d.ts +42 -0
- package/dist/src/otel/durable-metrics.d.ts.map +1 -0
- package/dist/src/otel/durable-metrics.js +75 -0
- package/dist/src/otel/durable-metrics.js.map +1 -0
- package/dist/src/otel/durable-otel.d.ts +20 -0
- package/dist/src/otel/durable-otel.d.ts.map +1 -0
- package/dist/src/otel/durable-otel.js +74 -0
- package/dist/src/otel/durable-otel.js.map +1 -0
- package/dist/src/otel/index.d.ts +4 -0
- package/dist/src/otel/index.d.ts.map +1 -0
- package/dist/src/otel/index.js +4 -0
- package/dist/src/otel/index.js.map +1 -0
- package/dist/src/otel/traceparent.d.ts +17 -0
- package/dist/src/otel/traceparent.d.ts.map +1 -0
- package/dist/src/otel/traceparent.js +21 -0
- package/dist/src/otel/traceparent.js.map +1 -0
- package/dist/src/pollers.d.ts +33 -0
- package/dist/src/pollers.d.ts.map +1 -0
- package/dist/src/pollers.js +76 -0
- package/dist/src/pollers.js.map +1 -0
- package/dist/src/protocol.d.ts +17 -0
- package/dist/src/protocol.d.ts.map +1 -0
- package/dist/src/protocol.js +47 -0
- package/dist/src/protocol.js.map +1 -0
- package/dist/src/queue.d.ts +113 -0
- package/dist/src/queue.d.ts.map +1 -0
- package/dist/src/queue.js +128 -0
- package/dist/src/queue.js.map +1 -0
- package/dist/src/remote-step-factory.d.ts +15 -0
- package/dist/src/remote-step-factory.d.ts.map +1 -0
- package/dist/src/remote-step-factory.js +12 -0
- package/dist/src/remote-step-factory.js.map +1 -0
- package/dist/src/remote-workflow-executor.d.ts +24 -0
- package/dist/src/remote-workflow-executor.d.ts.map +1 -0
- package/dist/src/remote-workflow-executor.js +70 -0
- package/dist/src/remote-workflow-executor.js.map +1 -0
- package/dist/src/scheduler.d.ts +67 -0
- package/dist/src/scheduler.d.ts.map +1 -0
- package/dist/src/scheduler.js +111 -0
- package/dist/src/scheduler.js.map +1 -0
- package/dist/src/search-attributes.d.ts +48 -0
- package/dist/src/search-attributes.d.ts.map +1 -0
- package/dist/src/search-attributes.js +98 -0
- package/dist/src/search-attributes.js.map +1 -0
- package/dist/src/singleton-gate.d.ts +44 -0
- package/dist/src/singleton-gate.d.ts.map +1 -0
- package/dist/src/singleton-gate.js +90 -0
- package/dist/src/singleton-gate.js.map +1 -0
- package/dist/src/step-logger.d.ts +9 -0
- package/dist/src/step-logger.d.ts.map +1 -0
- package/dist/src/step-logger.js +89 -0
- package/dist/src/step-logger.js.map +1 -0
- package/dist/src/stores/factory.d.ts +42 -0
- package/dist/src/stores/factory.d.ts.map +1 -0
- package/dist/src/stores/factory.js +29 -0
- package/dist/src/stores/factory.js.map +1 -0
- package/dist/src/stores/lucid-helpers.d.ts +11 -0
- package/dist/src/stores/lucid-helpers.d.ts.map +1 -0
- package/dist/src/stores/lucid-helpers.js +38 -0
- package/dist/src/stores/lucid-helpers.js.map +1 -0
- package/dist/src/stores/lucid-mappers.d.ts +58 -0
- package/dist/src/stores/lucid-mappers.d.ts.map +1 -0
- package/dist/src/stores/lucid-mappers.js +174 -0
- package/dist/src/stores/lucid-mappers.js.map +1 -0
- package/dist/src/stores/lucid-schema.d.ts +28 -0
- package/dist/src/stores/lucid-schema.d.ts.map +1 -0
- package/dist/src/stores/lucid-schema.js +115 -0
- package/dist/src/stores/lucid-schema.js.map +1 -0
- package/dist/src/stores/lucid.d.ts +69 -0
- package/dist/src/stores/lucid.d.ts.map +1 -0
- package/dist/src/stores/lucid.js +342 -0
- package/dist/src/stores/lucid.js.map +1 -0
- package/dist/src/telescope/dashboard.d.ts +15 -0
- package/dist/src/telescope/dashboard.d.ts.map +1 -0
- package/dist/src/telescope/dashboard.js +113 -0
- package/dist/src/telescope/dashboard.js.map +1 -0
- package/dist/src/telescope/data-providers.d.ts +20 -0
- package/dist/src/telescope/data-providers.d.ts.map +1 -0
- package/dist/src/telescope/data-providers.js +322 -0
- package/dist/src/telescope/data-providers.js.map +1 -0
- package/dist/src/telescope/extension.d.ts +22 -0
- package/dist/src/telescope/extension.d.ts.map +1 -0
- package/dist/src/telescope/extension.js +38 -0
- package/dist/src/telescope/extension.js.map +1 -0
- package/dist/src/telescope/index.d.ts +5 -0
- package/dist/src/telescope/index.d.ts.map +1 -0
- package/dist/src/telescope/index.js +4 -0
- package/dist/src/telescope/index.js.map +1 -0
- package/dist/src/telescope/telescope-sdk.d.ts +123 -0
- package/dist/src/telescope/telescope-sdk.d.ts.map +1 -0
- package/dist/src/telescope/telescope-sdk.js +12 -0
- package/dist/src/telescope/telescope-sdk.js.map +1 -0
- package/dist/src/test-helpers.d.ts +11 -0
- package/dist/src/test-helpers.d.ts.map +1 -0
- package/dist/src/test-helpers.js +12 -0
- package/dist/src/test-helpers.js.map +1 -0
- package/dist/src/testing/in-memory-state-store.d.ts +64 -0
- package/dist/src/testing/in-memory-state-store.d.ts.map +1 -0
- package/dist/src/testing/in-memory-state-store.js +259 -0
- package/dist/src/testing/in-memory-state-store.js.map +1 -0
- package/dist/src/testing/in-memory-transport.d.ts +25 -0
- package/dist/src/testing/in-memory-transport.d.ts.map +1 -0
- package/dist/src/testing/in-memory-transport.js +49 -0
- package/dist/src/testing/in-memory-transport.js.map +1 -0
- package/dist/src/testing-kit/admission-backend-conformance.d.ts +18 -0
- package/dist/src/testing-kit/admission-backend-conformance.d.ts.map +1 -0
- package/dist/src/testing-kit/admission-backend-conformance.js +81 -0
- package/dist/src/testing-kit/admission-backend-conformance.js.map +1 -0
- package/dist/src/testing-kit/assertions.d.ts +10 -0
- package/dist/src/testing-kit/assertions.d.ts.map +1 -0
- package/dist/src/testing-kit/assertions.js +41 -0
- package/dist/src/testing-kit/assertions.js.map +1 -0
- package/dist/src/testing-kit/harness.d.ts +28 -0
- package/dist/src/testing-kit/harness.d.ts.map +1 -0
- package/dist/src/testing-kit/harness.js +42 -0
- package/dist/src/testing-kit/harness.js.map +1 -0
- package/dist/src/testing-kit/index.d.ts +8 -0
- package/dist/src/testing-kit/index.d.ts.map +1 -0
- package/dist/src/testing-kit/index.js +8 -0
- package/dist/src/testing-kit/index.js.map +1 -0
- package/dist/src/testing-kit/replay.d.ts +22 -0
- package/dist/src/testing-kit/replay.d.ts.map +1 -0
- package/dist/src/testing-kit/replay.js +38 -0
- package/dist/src/testing-kit/replay.js.map +1 -0
- package/dist/src/testing-kit/state-store-conformance.d.ts +51 -0
- package/dist/src/testing-kit/state-store-conformance.d.ts.map +1 -0
- package/dist/src/testing-kit/state-store-conformance.js +430 -0
- package/dist/src/testing-kit/state-store-conformance.js.map +1 -0
- package/dist/src/testing-kit/steps.d.ts +5 -0
- package/dist/src/testing-kit/steps.d.ts.map +1 -0
- package/dist/src/testing-kit/steps.js +15 -0
- package/dist/src/testing-kit/steps.js.map +1 -0
- package/dist/src/testing-kit/transport-conformance.d.ts +16 -0
- package/dist/src/testing-kit/transport-conformance.d.ts.map +1 -0
- package/dist/src/testing-kit/transport-conformance.js +64 -0
- package/dist/src/testing-kit/transport-conformance.js.map +1 -0
- package/dist/src/tokens.d.ts +18 -0
- package/dist/src/tokens.d.ts.map +1 -0
- package/dist/src/tokens.js +18 -0
- package/dist/src/tokens.js.map +1 -0
- package/dist/src/transport-pool.d.ts +30 -0
- package/dist/src/transport-pool.d.ts.map +1 -0
- package/dist/src/transport-pool.js +82 -0
- package/dist/src/transport-pool.js.map +1 -0
- package/dist/src/transports/db-helpers.d.ts +10 -0
- package/dist/src/transports/db-helpers.d.ts.map +1 -0
- package/dist/src/transports/db-helpers.js +33 -0
- package/dist/src/transports/db-helpers.js.map +1 -0
- package/dist/src/transports/db-schema.d.ts +28 -0
- package/dist/src/transports/db-schema.d.ts.map +1 -0
- package/dist/src/transports/db-schema.js +98 -0
- package/dist/src/transports/db-schema.js.map +1 -0
- package/dist/src/transports/db.d.ts +81 -0
- package/dist/src/transports/db.d.ts.map +1 -0
- package/dist/src/transports/db.js +340 -0
- package/dist/src/transports/db.js.map +1 -0
- package/dist/src/transports/factory.d.ts +79 -0
- package/dist/src/transports/factory.d.ts.map +1 -0
- package/dist/src/transports/factory.js +57 -0
- package/dist/src/transports/factory.js.map +1 -0
- package/dist/src/transports/queue-mock-adapter.d.ts +39 -0
- package/dist/src/transports/queue-mock-adapter.d.ts.map +1 -0
- package/dist/src/transports/queue-mock-adapter.js +86 -0
- package/dist/src/transports/queue-mock-adapter.js.map +1 -0
- package/dist/src/transports/queue.d.ts +84 -0
- package/dist/src/transports/queue.d.ts.map +1 -0
- package/dist/src/transports/queue.js +210 -0
- package/dist/src/transports/queue.js.map +1 -0
- package/dist/src/workflow-ctx.d.ts +64 -0
- package/dist/src/workflow-ctx.d.ts.map +1 -0
- package/dist/src/workflow-ctx.js +457 -0
- package/dist/src/workflow-ctx.js.map +1 -0
- package/dist/src/workflow-ref.d.ts +34 -0
- package/dist/src/workflow-ref.d.ts.map +1 -0
- package/dist/src/workflow-ref.js +28 -0
- package/dist/src/workflow-ref.js.map +1 -0
- package/dist/stubs/config/durable.stub +49 -0
- package/dist/stubs/config/durable_dashboard.stub +17 -0
- package/dist/stubs/database/migrations/create_durable_tables.stub +87 -0
- package/dist/stubs/database/migrations/create_durable_transport_tables.stub +75 -0
- package/dist/stubs/main.d.ts +3 -0
- package/dist/stubs/main.d.ts.map +1 -0
- package/dist/stubs/main.js +4 -0
- package/dist/stubs/main.js.map +1 -0
- package/package.json +154 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-injection tokens. Adapters bind their implementations to these so `core` and
|
|
3
|
+
* `@dudousxd/nestjs-durable` depend only on the interfaces in `./interfaces`.
|
|
4
|
+
*
|
|
5
|
+
* These use `Symbol.for(key)` (the global symbol registry), NOT `Symbol(key)`, so the token is the
|
|
6
|
+
* SAME instance no matter how many times `core` is evaluated in a process. A consumer can hold more
|
|
7
|
+
* than one physical copy of `core` at runtime — pnpm peer-dependency multiplexing installs a
|
|
8
|
+
* separate virtual copy per distinct peer set, and the dual ESM/CJS build can be loaded once as
|
|
9
|
+
* `import` (`index.js`) and once as `require` (`index.cjs`). A plain `Symbol()` would mint a
|
|
10
|
+
* DISTINCT token per copy, so `DurableModule` (provider) and `DashboardService` / a store adapter
|
|
11
|
+
* (injector) could resolve different symbols → Nest can't satisfy the dependency
|
|
12
|
+
* (`STATE_STORE is not available in the DurableApiModule context`). A registered symbol collapses
|
|
13
|
+
* them to one. Mirrors the `CONTEXT_ACCESSOR` token in `@dudousxd/nestjs-durable`'s `tokens.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export const STATE_STORE = Symbol.for('@agora/durable:STATE_STORE');
|
|
16
|
+
export const TRANSPORT = Symbol.for('@agora/durable:TRANSPORT');
|
|
17
|
+
export const DURABLE_OPTIONS = Symbol.for('@agora/durable:DURABLE_OPTIONS');
|
|
18
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { GroupHealth, Heartbeat, NamedTransport, RemoteTask, StepResult, WorkflowStepEvent } from './interfaces.js';
|
|
2
|
+
/**
|
|
3
|
+
* An ordered pool of named transports. The engine dispatches on the first and fails over to the
|
|
4
|
+
* next on a dispatch error; a step can pin one by id. Pure transport plumbing — no run lifecycle —
|
|
5
|
+
* so it lives apart from the engine.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TransportPool {
|
|
8
|
+
private readonly transports;
|
|
9
|
+
constructor(transports: NamedTransport[]);
|
|
10
|
+
get size(): number;
|
|
11
|
+
/** Register the engine's result/heartbeat/step-event handlers on EVERY transport — a result can come
|
|
12
|
+
* back on whichever one delivered the task, so failover stays symmetric. `onStepEvent` is wired only
|
|
13
|
+
* on transports that carry streamed workflow step lifecycle (BullMQ); others simply skip it. */
|
|
14
|
+
bind(onResult: (result: StepResult) => Promise<void>, onHeartbeat: (beat: Heartbeat) => Promise<void>, onStepEvent?: (event: WorkflowStepEvent) => Promise<void>): void;
|
|
15
|
+
/**
|
|
16
|
+
* Dispatch `task` over the pool: try the preferred (or first) transport, fail over to the next on
|
|
17
|
+
* a dispatch error, and stamp the task with the id of the transport that accepted it (so a worker
|
|
18
|
+
* replies on the matching one). Throws if every transport fails.
|
|
19
|
+
*/
|
|
20
|
+
dispatch(task: Omit<RemoteTask, 'transport'>, preferId?: string): Promise<void>;
|
|
21
|
+
/** Worker-health for `group`, merged across every transport that can report it (a group's queue
|
|
22
|
+
* and its workers may live on any pinned transport). Undefined when no transport implements
|
|
23
|
+
* `groupHealth` (e.g. a pure in-process transport — nothing to introspect). */
|
|
24
|
+
groupHealth(group: string): Promise<GroupHealth | undefined>;
|
|
25
|
+
/** Distinct worker groups with a live heartbeat, merged across every transport that can report it. */
|
|
26
|
+
listWorkerGroups(): Promise<string[]>;
|
|
27
|
+
/** Pinned `preferId` first, then the rest (failover order). */
|
|
28
|
+
private ordered;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=transport-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-pool.d.ts","sourceRoot":"","sources":["../../src/transport-pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AAEzB;;;;GAIG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,cAAc,EAAE;IAEzD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;qGAEiG;IACjG,IAAI,CACF,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,EAC/C,WAAW,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,EAC/C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACxD,IAAI;IAUP;;;;OAIG;IACG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAarF;;oFAEgF;IAC1E,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAalE,sGAAsG;IAChG,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAU3C,+DAA+D;IAC/D,OAAO,CAAC,OAAO;CAMhB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An ordered pool of named transports. The engine dispatches on the first and fails over to the
|
|
3
|
+
* next on a dispatch error; a step can pin one by id. Pure transport plumbing — no run lifecycle —
|
|
4
|
+
* so it lives apart from the engine.
|
|
5
|
+
*/
|
|
6
|
+
export class TransportPool {
|
|
7
|
+
transports;
|
|
8
|
+
constructor(transports) {
|
|
9
|
+
this.transports = transports;
|
|
10
|
+
}
|
|
11
|
+
get size() {
|
|
12
|
+
return this.transports.length;
|
|
13
|
+
}
|
|
14
|
+
/** Register the engine's result/heartbeat/step-event handlers on EVERY transport — a result can come
|
|
15
|
+
* back on whichever one delivered the task, so failover stays symmetric. `onStepEvent` is wired only
|
|
16
|
+
* on transports that carry streamed workflow step lifecycle (BullMQ); others simply skip it. */
|
|
17
|
+
bind(onResult, onHeartbeat, onStepEvent) {
|
|
18
|
+
for (const { transport } of this.transports) {
|
|
19
|
+
transport.onResult(onResult);
|
|
20
|
+
transport.onHeartbeat(onHeartbeat);
|
|
21
|
+
if (onStepEvent && transport.onStepEvent) {
|
|
22
|
+
transport.onStepEvent(onStepEvent);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Dispatch `task` over the pool: try the preferred (or first) transport, fail over to the next on
|
|
28
|
+
* a dispatch error, and stamp the task with the id of the transport that accepted it (so a worker
|
|
29
|
+
* replies on the matching one). Throws if every transport fails.
|
|
30
|
+
*/
|
|
31
|
+
async dispatch(task, preferId) {
|
|
32
|
+
let lastErr;
|
|
33
|
+
for (const { id, transport } of this.ordered(preferId)) {
|
|
34
|
+
try {
|
|
35
|
+
await transport.dispatch({ ...task, transport: id });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
lastErr = err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw lastErr ?? new Error('no transport accepted the dispatch');
|
|
43
|
+
}
|
|
44
|
+
/** Worker-health for `group`, merged across every transport that can report it (a group's queue
|
|
45
|
+
* and its workers may live on any pinned transport). Undefined when no transport implements
|
|
46
|
+
* `groupHealth` (e.g. a pure in-process transport — nothing to introspect). */
|
|
47
|
+
async groupHealth(group) {
|
|
48
|
+
const reports = [];
|
|
49
|
+
for (const { transport } of this.transports) {
|
|
50
|
+
if (transport.groupHealth)
|
|
51
|
+
reports.push(await transport.groupHealth(group));
|
|
52
|
+
}
|
|
53
|
+
if (reports.length === 0)
|
|
54
|
+
return undefined;
|
|
55
|
+
return {
|
|
56
|
+
group,
|
|
57
|
+
depth: reports.reduce((sum, r) => sum + r.depth, 0),
|
|
58
|
+
liveWorkers: reports.flatMap((r) => r.liveWorkers),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Distinct worker groups with a live heartbeat, merged across every transport that can report it. */
|
|
62
|
+
async listWorkerGroups() {
|
|
63
|
+
const groups = new Set();
|
|
64
|
+
for (const { transport } of this.transports) {
|
|
65
|
+
if (transport.listWorkerGroups) {
|
|
66
|
+
for (const g of await transport.listWorkerGroups())
|
|
67
|
+
groups.add(g);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [...groups];
|
|
71
|
+
}
|
|
72
|
+
/** Pinned `preferId` first, then the rest (failover order). */
|
|
73
|
+
ordered(preferId) {
|
|
74
|
+
if (!preferId)
|
|
75
|
+
return this.transports;
|
|
76
|
+
const pref = this.transports.filter((t) => t.id === preferId);
|
|
77
|
+
if (pref.length === 0)
|
|
78
|
+
throw new Error(`transport "${preferId}" is not registered`);
|
|
79
|
+
return [...pref, ...this.transports.filter((t) => t.id !== preferId)];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=transport-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-pool.js","sourceRoot":"","sources":["../../src/transport-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Database } from '@adonisjs/lucid/database';
|
|
2
|
+
/**
|
|
3
|
+
* Build a standalone Lucid `Database` over an in-memory SQLite (`better-sqlite3`) — the "using Lucid
|
|
4
|
+
* outside an app" pattern. We construct `Database(config, logger, emitter)` directly (the three args
|
|
5
|
+
* Lucid's provider passes) so the transport runs against real SQL with no AdonisJS app boot.
|
|
6
|
+
*/
|
|
7
|
+
export declare function makeMemoryDb(): Database;
|
|
8
|
+
/** A fresh in-memory db with the transport tables already created. */
|
|
9
|
+
export declare function makeTransportDb(): Promise<Database>;
|
|
10
|
+
//# sourceMappingURL=db-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-helpers.d.ts","sourceRoot":"","sources":["../../../src/transports/db-helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,QAAQ,CAoBvC;AAED,sEAAsE;AACtE,wBAAsB,eAAe,IAAI,OAAO,CAAC,QAAQ,CAAC,CAIzD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Emitter } from '@adonisjs/core/events';
|
|
2
|
+
import { Logger } from '@adonisjs/core/logger';
|
|
3
|
+
import { Database } from '@adonisjs/lucid/database';
|
|
4
|
+
import { createDurableTransportTables } from './db-schema.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build a standalone Lucid `Database` over an in-memory SQLite (`better-sqlite3`) — the "using Lucid
|
|
7
|
+
* outside an app" pattern. We construct `Database(config, logger, emitter)` directly (the three args
|
|
8
|
+
* Lucid's provider passes) so the transport runs against real SQL with no AdonisJS app boot.
|
|
9
|
+
*/
|
|
10
|
+
export function makeMemoryDb() {
|
|
11
|
+
const logger = new Logger({ enabled: false });
|
|
12
|
+
const emitter = new Emitter(undefined);
|
|
13
|
+
return new Database({
|
|
14
|
+
connection: 'sqlite',
|
|
15
|
+
connections: {
|
|
16
|
+
sqlite: {
|
|
17
|
+
client: 'better-sqlite3',
|
|
18
|
+
connection: { filename: ':memory:' },
|
|
19
|
+
useNullAsDefault: true,
|
|
20
|
+
// A `:memory:` SQLite db is per-connection: pin the pool to ONE connection so every query
|
|
21
|
+
// (and the schema) hits the same in-memory database.
|
|
22
|
+
pool: { min: 1, max: 1 },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}, logger, emitter);
|
|
26
|
+
}
|
|
27
|
+
/** A fresh in-memory db with the transport tables already created. */
|
|
28
|
+
export async function makeTransportDb() {
|
|
29
|
+
const db = makeMemoryDb();
|
|
30
|
+
await createDurableTransportTables(db);
|
|
31
|
+
return db;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=db-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-helpers.js","sourceRoot":"","sources":["../../../src/transports/db-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAkB,CAAC,CAAC;IAChD,OAAO,IAAI,QAAQ,CACjB;QACE,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE;YACX,MAAM,EAAE;gBACN,MAAM,EAAE,gBAAgB;gBACxB,UAAU,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE;gBACpC,gBAAgB,EAAE,IAAI;gBACtB,0FAA0F;gBAC1F,qDAAqD;gBACrD,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;aACzB;SACF;KACF,EACD,MAAM,EACN,OAAO,CACR,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IAC1B,MAAM,4BAA4B,CAAC,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Database } from '@adonisjs/lucid/database';
|
|
2
|
+
/**
|
|
3
|
+
* The DB transport's table names. Distinct from the durable *store* tables (`durable_workflow_runs`
|
|
4
|
+
* etc.) — these carry the point-to-point work channels (tasks / results / heartbeats / control), so
|
|
5
|
+
* the transport can share one database with the store without colliding.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TRANSPORT_TABLES: {
|
|
8
|
+
readonly tasks: "durable_transport_tasks";
|
|
9
|
+
readonly results: "durable_transport_results";
|
|
10
|
+
readonly heartbeats: "durable_transport_heartbeats";
|
|
11
|
+
readonly control: "durable_transport_control";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Idempotent DDL for the four transport tables, via Lucid's schema builder (Knex). Portable across
|
|
15
|
+
* SQLite / Postgres / MySQL: JSON payloads (`input`/`output`/`error`/`payload`) are stored as TEXT
|
|
16
|
+
* and (de)serialized by the transport, and every timestamp is an epoch-ms `bigInteger`, so there's
|
|
17
|
+
* no dependency on a dialect's native JSON/date type.
|
|
18
|
+
*
|
|
19
|
+
* Each row is a one-shot message claimed by exactly one consumer (atomic conditional UPDATE on
|
|
20
|
+
* `claimed_by`) and then deleted once handled — the DB is the queue.
|
|
21
|
+
*
|
|
22
|
+
* Call this on boot or once at deploy time. For an AdonisJS app prefer the published migration
|
|
23
|
+
* (`node ace configure @adonis-agora/durable`); this helper is for standalone use and tests.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createDurableTransportTables(db: Database): Promise<void>;
|
|
26
|
+
/** Drop every transport table. Used by tests and the migration `down`. */
|
|
27
|
+
export declare function dropDurableTransportTables(db: Database): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=db-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-schema.d.ts","sourceRoot":"","sources":["../../../src/transports/db-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAsB,4BAA4B,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE9E;AAED,0EAA0E;AAC1E,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DB transport's table names. Distinct from the durable *store* tables (`durable_workflow_runs`
|
|
3
|
+
* etc.) — these carry the point-to-point work channels (tasks / results / heartbeats / control), so
|
|
4
|
+
* the transport can share one database with the store without colliding.
|
|
5
|
+
*/
|
|
6
|
+
export const TRANSPORT_TABLES = {
|
|
7
|
+
tasks: 'durable_transport_tasks',
|
|
8
|
+
results: 'durable_transport_results',
|
|
9
|
+
heartbeats: 'durable_transport_heartbeats',
|
|
10
|
+
control: 'durable_transport_control',
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Idempotent DDL for the four transport tables, via Lucid's schema builder (Knex). Portable across
|
|
14
|
+
* SQLite / Postgres / MySQL: JSON payloads (`input`/`output`/`error`/`payload`) are stored as TEXT
|
|
15
|
+
* and (de)serialized by the transport, and every timestamp is an epoch-ms `bigInteger`, so there's
|
|
16
|
+
* no dependency on a dialect's native JSON/date type.
|
|
17
|
+
*
|
|
18
|
+
* Each row is a one-shot message claimed by exactly one consumer (atomic conditional UPDATE on
|
|
19
|
+
* `claimed_by`) and then deleted once handled — the DB is the queue.
|
|
20
|
+
*
|
|
21
|
+
* Call this on boot or once at deploy time. For an AdonisJS app prefer the published migration
|
|
22
|
+
* (`node ace configure @adonis-agora/durable`); this helper is for standalone use and tests.
|
|
23
|
+
*/
|
|
24
|
+
export async function createDurableTransportTables(db) {
|
|
25
|
+
// Knex's schema builder is stateful — take a FRESH `db.connection().schema` per hasTable/createTable
|
|
26
|
+
// so each DDL statement executes exactly once.
|
|
27
|
+
const conn = () => db.connection().schema;
|
|
28
|
+
// ── tasks: engine → worker (a RemoteTask) ──────────────────────────────────
|
|
29
|
+
if (!(await conn().hasTable(TRANSPORT_TABLES.tasks))) {
|
|
30
|
+
await conn().createTable(TRANSPORT_TABLES.tasks, (table) => {
|
|
31
|
+
table.string('step_id').primary();
|
|
32
|
+
table.string('run_id').notNullable();
|
|
33
|
+
table.integer('seq').notNullable();
|
|
34
|
+
table.string('name').notNullable();
|
|
35
|
+
table.string('grp').notNullable();
|
|
36
|
+
table.text('input');
|
|
37
|
+
table.string('traceparent');
|
|
38
|
+
table.text('context');
|
|
39
|
+
table.string('transport');
|
|
40
|
+
table.integer('attempt').notNullable();
|
|
41
|
+
table.string('claimed_by');
|
|
42
|
+
table.bigInteger('claimed_at');
|
|
43
|
+
table.bigInteger('created_at').notNullable();
|
|
44
|
+
table.index(['grp', 'claimed_at', 'created_at'], 'durable_transport_tasks_grp_idx');
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// ── results: worker → engine (a StepResult) ────────────────────────────────
|
|
48
|
+
if (!(await conn().hasTable(TRANSPORT_TABLES.results))) {
|
|
49
|
+
await conn().createTable(TRANSPORT_TABLES.results, (table) => {
|
|
50
|
+
table.string('step_id').primary();
|
|
51
|
+
table.string('run_id').notNullable();
|
|
52
|
+
table.integer('seq').notNullable();
|
|
53
|
+
table.string('status').notNullable();
|
|
54
|
+
table.text('output');
|
|
55
|
+
table.text('error');
|
|
56
|
+
table.bigInteger('started_at');
|
|
57
|
+
table.text('events');
|
|
58
|
+
table.string('claimed_by');
|
|
59
|
+
table.bigInteger('claimed_at');
|
|
60
|
+
table.bigInteger('created_at').notNullable();
|
|
61
|
+
table.index(['claimed_at', 'created_at'], 'durable_transport_results_idx');
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// ── heartbeats: worker → engine (liveness for a long step) ─────────────────
|
|
65
|
+
if (!(await conn().hasTable(TRANSPORT_TABLES.heartbeats))) {
|
|
66
|
+
await conn().createTable(TRANSPORT_TABLES.heartbeats, (table) => {
|
|
67
|
+
table.increments('id').primary();
|
|
68
|
+
table.string('run_id').notNullable();
|
|
69
|
+
table.integer('seq').notNullable();
|
|
70
|
+
table.string('step_id').notNullable();
|
|
71
|
+
table.string('grp').notNullable();
|
|
72
|
+
table.string('claimed_by');
|
|
73
|
+
table.bigInteger('claimed_at');
|
|
74
|
+
table.bigInteger('created_at').notNullable();
|
|
75
|
+
table.index(['claimed_at', 'created_at'], 'durable_transport_heartbeats_idx');
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
// ── control: best-effort control-plane messages (single-consumer) ──────────
|
|
79
|
+
if (!(await conn().hasTable(TRANSPORT_TABLES.control))) {
|
|
80
|
+
await conn().createTable(TRANSPORT_TABLES.control, (table) => {
|
|
81
|
+
table.increments('id').primary();
|
|
82
|
+
table.text('payload').notNullable();
|
|
83
|
+
table.string('claimed_by');
|
|
84
|
+
table.bigInteger('claimed_at');
|
|
85
|
+
table.bigInteger('created_at').notNullable();
|
|
86
|
+
table.index(['claimed_at', 'created_at'], 'durable_transport_control_idx');
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Drop every transport table. Used by tests and the migration `down`. */
|
|
91
|
+
export async function dropDurableTransportTables(db) {
|
|
92
|
+
const conn = () => db.connection().schema;
|
|
93
|
+
await conn().dropTableIfExists(TRANSPORT_TABLES.control);
|
|
94
|
+
await conn().dropTableIfExists(TRANSPORT_TABLES.heartbeats);
|
|
95
|
+
await conn().dropTableIfExists(TRANSPORT_TABLES.results);
|
|
96
|
+
await conn().dropTableIfExists(TRANSPORT_TABLES.tasks);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=db-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-schema.js","sourceRoot":"","sources":["../../../src/transports/db-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Database } from '@adonisjs/lucid/database';
|
|
2
|
+
import { type ControlMessage, type ControlPlane, type Heartbeat, type RemoteTask, type StepResult, type Transport } from '../interfaces.js';
|
|
3
|
+
import { type StepHandler } from '../protocol.js';
|
|
4
|
+
export interface DbTransportOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The Lucid `Database` to read/write. Use the app's own `db` service (no broker, no extra
|
|
7
|
+
* connection) — the database you already have IS the queue.
|
|
8
|
+
*/
|
|
9
|
+
db: Database;
|
|
10
|
+
/**
|
|
11
|
+
* The worker group this instance serves. Required to register {@link DbTransport.handle} consumers
|
|
12
|
+
* — the task poll loop claims rows for this group. Omit on an engine-only instance that just
|
|
13
|
+
* dispatches + consumes results/heartbeats.
|
|
14
|
+
*/
|
|
15
|
+
group?: string;
|
|
16
|
+
/** Lucid connection name to use. Defaults to the `Database` default connection. */
|
|
17
|
+
connectionName?: string;
|
|
18
|
+
/** Poll interval (ms) for the result/task/heartbeat/control loops. Default 200ms. */
|
|
19
|
+
pollIntervalMs?: number;
|
|
20
|
+
/** How long a claimed-but-unfinished row is owned before it's reclaimable (crash recovery). Default 30s. */
|
|
21
|
+
leaseMs?: number;
|
|
22
|
+
/** Max rows claimed per poll. Default 20. */
|
|
23
|
+
batchSize?: number;
|
|
24
|
+
/** Create the transport tables on first use if missing. Default true. */
|
|
25
|
+
autoCreate?: boolean;
|
|
26
|
+
/** Stable id for this process (stamped on heartbeats / control `from` / `claimed_by`). Default random. */
|
|
27
|
+
instanceId?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A poll-based, DB-table-backed {@link Transport} (and best-effort {@link ControlPlane}) over
|
|
31
|
+
* AdonisJS **Lucid** — DBOS-style. Instead of a broker (Redis/SQS), remote steps are **rows** in the
|
|
32
|
+
* same database the durable store already uses: `dispatch` inserts a task row; a worker poller claims
|
|
33
|
+
* unclaimed task rows (atomic conditional `UPDATE … SET claimed_by`), runs the handler via
|
|
34
|
+
* {@link runStepHandler}, and writes a result row the engine polls. Heartbeats and control messages
|
|
35
|
+
* ride their own tables. Zero new infrastructure — often the simplest production transport.
|
|
36
|
+
*
|
|
37
|
+
* Claiming is portable across SQLite / Postgres / MySQL: it uses a compare-and-set UPDATE on
|
|
38
|
+
* `claimed_by`/`claimed_at` (no `FOR UPDATE SKIP LOCKED`), so multiple workers never double-process a
|
|
39
|
+
* row, and a crashed worker's claim is reclaimed once its lease (`leaseMs`) expires.
|
|
40
|
+
*
|
|
41
|
+
* Trade-off vs a real broker: throughput is bounded by polling + row contention — great for
|
|
42
|
+
* workflow/pipeline scale (modest rate, long steps), not for high-fanout firehoses. The
|
|
43
|
+
* {@link ControlPlane} here is single-consumer (one row → one poller), correct for a single engine
|
|
44
|
+
* instance but NOT a true broadcast.
|
|
45
|
+
*
|
|
46
|
+
* Run one instance engine-side (`onResult` + `dispatch`) and one per worker process (`handle()` for
|
|
47
|
+
* its group). Call {@link start} to begin the engine-side pollers; `handle()` auto-starts the task
|
|
48
|
+
* loop. The wire payloads are the documented `RemoteTask`/`StepResult` JSON.
|
|
49
|
+
*
|
|
50
|
+
* Usually you don't construct this directly: `config/durable.ts` selects it via
|
|
51
|
+
* `transports.db({ ... })` and the provider builds it for you.
|
|
52
|
+
*/
|
|
53
|
+
export declare class DbTransport implements Transport, ControlPlane {
|
|
54
|
+
#private;
|
|
55
|
+
constructor(options: DbTransportOptions);
|
|
56
|
+
/** Stable id stamped on heartbeats, control `from`, and `claimed_by`. */
|
|
57
|
+
get instanceId(): string;
|
|
58
|
+
dispatch(task: RemoteTask): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Register a step handler (worker side). Starts this group's task poll loop on the first call —
|
|
61
|
+
* each claimed task runs through {@link runStepHandler} and its result is written for the engine.
|
|
62
|
+
*/
|
|
63
|
+
handle(name: string, fn: StepHandler): void;
|
|
64
|
+
/** Worker side: publish a liveness heartbeat for an in-flight long step. */
|
|
65
|
+
heartbeat(beat: Heartbeat): Promise<void>;
|
|
66
|
+
onResult(handler: (result: StepResult) => Promise<void>): void;
|
|
67
|
+
onHeartbeat(handler: (beat: Heartbeat) => Promise<void>): void;
|
|
68
|
+
publishControl(msg: ControlMessage): Promise<void>;
|
|
69
|
+
onControl(handler: (msg: ControlMessage) => void): void;
|
|
70
|
+
/**
|
|
71
|
+
* No-op convenience: the loops auto-start when `onResult`/`onHeartbeat`/`onControl`/`handle` are
|
|
72
|
+
* registered. Exposed for symmetry and to mirror broker transports — call it after wiring handlers
|
|
73
|
+
* if you prefer an explicit start. Returns once the schema is ready.
|
|
74
|
+
*/
|
|
75
|
+
start(): Promise<void>;
|
|
76
|
+
/** Stop every poll loop. Does not close the shared `Database`. */
|
|
77
|
+
stop(): Promise<void>;
|
|
78
|
+
/** Stop the pollers (alias of {@link stop} for the `Transport.close` contract). */
|
|
79
|
+
close(): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/transports/db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAKzD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,gBAAgB,CAAC;AAqElE,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,EAAE,EAAE,QAAQ,CAAC;IACb;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4GAA4G;IAC5G,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0GAA0G;IAC1G,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,WAAY,YAAW,SAAS,EAAE,YAAY;;gBAc7C,OAAO,EAAE,kBAAkB;IAYvC,yEAAyE;IACzE,IAAI,UAAU,IAAI,MAAM,CAEvB;IAoBK,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B/C;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI;IAW3C,4EAA4E;IACtE,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA4D/C,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI9D,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAyCxD,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxD,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAkFvD;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,kEAAkE;IAC5D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,mFAAmF;IAC7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|