@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,340 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { Pollers } from '../pollers.js';
|
|
3
|
+
import { runStepHandler } from '../protocol.js';
|
|
4
|
+
import { TRANSPORT_TABLES, createDurableTransportTables } from './db-schema.js';
|
|
5
|
+
/**
|
|
6
|
+
* The wire payloads carried in the DB transport's table rows. Everything crossing the DB is plain
|
|
7
|
+
* JSON — JSON columns are stored as TEXT, so these helpers (de)serialize through
|
|
8
|
+
* `JSON.stringify`/`JSON.parse`: only JSON-safe values survive (functions, symbols, `undefined`
|
|
9
|
+
* members are dropped exactly as a real broker would drop them).
|
|
10
|
+
*/
|
|
11
|
+
/** Serialize a value to a JSON string, or `null` for `undefined` (so a TEXT column round-trips). */
|
|
12
|
+
function toJson(value) {
|
|
13
|
+
return value === undefined ? null : JSON.stringify(value);
|
|
14
|
+
}
|
|
15
|
+
/** Parse a TEXT column we previously wrote with {@link toJson}. `null`/empty → `undefined`. */
|
|
16
|
+
function fromJson(value) {
|
|
17
|
+
if (value === null || value === undefined || value === '')
|
|
18
|
+
return undefined;
|
|
19
|
+
return JSON.parse(value);
|
|
20
|
+
}
|
|
21
|
+
/** Default poll interval (ms) for the result/task/heartbeat/control loops. */
|
|
22
|
+
const DEFAULT_POLL_INTERVAL_MS = 200;
|
|
23
|
+
/** Default lease window (ms): a claimed-but-not-deleted row is reclaimable after this (crash recovery). */
|
|
24
|
+
const DEFAULT_LEASE_MS = 30_000;
|
|
25
|
+
/** Default max rows claimed per poll. */
|
|
26
|
+
const DEFAULT_BATCH_SIZE = 20;
|
|
27
|
+
const DEFAULT_LOG = (err) => console.error('[DbTransport] poll failed', err);
|
|
28
|
+
/**
|
|
29
|
+
* A poll-based, DB-table-backed {@link Transport} (and best-effort {@link ControlPlane}) over
|
|
30
|
+
* AdonisJS **Lucid** — DBOS-style. Instead of a broker (Redis/SQS), remote steps are **rows** in the
|
|
31
|
+
* same database the durable store already uses: `dispatch` inserts a task row; a worker poller claims
|
|
32
|
+
* unclaimed task rows (atomic conditional `UPDATE … SET claimed_by`), runs the handler via
|
|
33
|
+
* {@link runStepHandler}, and writes a result row the engine polls. Heartbeats and control messages
|
|
34
|
+
* ride their own tables. Zero new infrastructure — often the simplest production transport.
|
|
35
|
+
*
|
|
36
|
+
* Claiming is portable across SQLite / Postgres / MySQL: it uses a compare-and-set UPDATE on
|
|
37
|
+
* `claimed_by`/`claimed_at` (no `FOR UPDATE SKIP LOCKED`), so multiple workers never double-process a
|
|
38
|
+
* row, and a crashed worker's claim is reclaimed once its lease (`leaseMs`) expires.
|
|
39
|
+
*
|
|
40
|
+
* Trade-off vs a real broker: throughput is bounded by polling + row contention — great for
|
|
41
|
+
* workflow/pipeline scale (modest rate, long steps), not for high-fanout firehoses. The
|
|
42
|
+
* {@link ControlPlane} here is single-consumer (one row → one poller), correct for a single engine
|
|
43
|
+
* instance but NOT a true broadcast.
|
|
44
|
+
*
|
|
45
|
+
* Run one instance engine-side (`onResult` + `dispatch`) and one per worker process (`handle()` for
|
|
46
|
+
* its group). Call {@link start} to begin the engine-side pollers; `handle()` auto-starts the task
|
|
47
|
+
* loop. The wire payloads are the documented `RemoteTask`/`StepResult` JSON.
|
|
48
|
+
*
|
|
49
|
+
* Usually you don't construct this directly: `config/durable.ts` selects it via
|
|
50
|
+
* `transports.db({ ... })` and the provider builds it for you.
|
|
51
|
+
*/
|
|
52
|
+
export class DbTransport {
|
|
53
|
+
#db;
|
|
54
|
+
#group;
|
|
55
|
+
#connectionName;
|
|
56
|
+
#pollIntervalMs;
|
|
57
|
+
#leaseMs;
|
|
58
|
+
#batchSize;
|
|
59
|
+
#autoCreate;
|
|
60
|
+
#instanceId;
|
|
61
|
+
#handlers = new Map();
|
|
62
|
+
#pollers;
|
|
63
|
+
#schemaReady;
|
|
64
|
+
#taskLoop;
|
|
65
|
+
constructor(options) {
|
|
66
|
+
this.#db = options.db;
|
|
67
|
+
this.#group = options.group;
|
|
68
|
+
this.#connectionName = options.connectionName;
|
|
69
|
+
this.#pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
70
|
+
this.#leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;
|
|
71
|
+
this.#batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
72
|
+
this.#autoCreate = options.autoCreate ?? true;
|
|
73
|
+
this.#instanceId = options.instanceId ?? randomUUID();
|
|
74
|
+
this.#pollers = new Pollers(this.#pollIntervalMs, DEFAULT_LOG);
|
|
75
|
+
}
|
|
76
|
+
/** Stable id stamped on heartbeats, control `from`, and `claimed_by`. */
|
|
77
|
+
get instanceId() {
|
|
78
|
+
return this.#instanceId;
|
|
79
|
+
}
|
|
80
|
+
#client() {
|
|
81
|
+
return this.#connectionName ? this.#db.connection(this.#connectionName) : this.#db.connection();
|
|
82
|
+
}
|
|
83
|
+
#now() {
|
|
84
|
+
return Date.now();
|
|
85
|
+
}
|
|
86
|
+
#ensureSchema() {
|
|
87
|
+
if (!this.#autoCreate)
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
if (!this.#schemaReady)
|
|
90
|
+
this.#schemaReady = createDurableTransportTables(this.#db);
|
|
91
|
+
return this.#schemaReady;
|
|
92
|
+
}
|
|
93
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
94
|
+
// engine → worker
|
|
95
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
96
|
+
async dispatch(task) {
|
|
97
|
+
await this.#ensureSchema();
|
|
98
|
+
// Idempotent: a redelivered dispatch for the same step_id is ignored (the PK already exists).
|
|
99
|
+
// `onConflict().ignore()` is a Knex feature not surfaced on Lucid's insert contract, so we use
|
|
100
|
+
// the underlying Knex builder (`.knexQuery`).
|
|
101
|
+
await this.#client()
|
|
102
|
+
.insertQuery()
|
|
103
|
+
.table(TRANSPORT_TABLES.tasks)
|
|
104
|
+
.knexQuery.insert({
|
|
105
|
+
step_id: task.stepId,
|
|
106
|
+
run_id: task.runId,
|
|
107
|
+
seq: task.seq,
|
|
108
|
+
name: task.name,
|
|
109
|
+
grp: task.group,
|
|
110
|
+
input: toJson(task.input),
|
|
111
|
+
traceparent: task.traceparent ?? null,
|
|
112
|
+
context: toJson(task.context),
|
|
113
|
+
transport: task.transport ?? null,
|
|
114
|
+
attempt: task.attempt,
|
|
115
|
+
claimed_by: null,
|
|
116
|
+
claimed_at: null,
|
|
117
|
+
created_at: this.#now(),
|
|
118
|
+
})
|
|
119
|
+
.onConflict('step_id')
|
|
120
|
+
.ignore();
|
|
121
|
+
}
|
|
122
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
123
|
+
// worker side — register a handler, claim + run tasks, write results
|
|
124
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
125
|
+
/**
|
|
126
|
+
* Register a step handler (worker side). Starts this group's task poll loop on the first call —
|
|
127
|
+
* each claimed task runs through {@link runStepHandler} and its result is written for the engine.
|
|
128
|
+
*/
|
|
129
|
+
handle(name, fn) {
|
|
130
|
+
if (!this.#group) {
|
|
131
|
+
throw new Error('DbTransport needs a `group` option to register handlers');
|
|
132
|
+
}
|
|
133
|
+
this.#handlers.set(name, fn);
|
|
134
|
+
if (!this.#taskLoop) {
|
|
135
|
+
const group = this.#group;
|
|
136
|
+
this.#taskLoop = this.#pollers.start(async () => (await this.#drainTasks(group)) > 0);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** Worker side: publish a liveness heartbeat for an in-flight long step. */
|
|
140
|
+
async heartbeat(beat) {
|
|
141
|
+
await this.#ensureSchema();
|
|
142
|
+
await this.#client().table(TRANSPORT_TABLES.heartbeats).insert({
|
|
143
|
+
run_id: beat.runId,
|
|
144
|
+
seq: beat.seq,
|
|
145
|
+
step_id: beat.stepId,
|
|
146
|
+
grp: beat.group,
|
|
147
|
+
claimed_by: null,
|
|
148
|
+
claimed_at: null,
|
|
149
|
+
created_at: this.#now(),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async #drainTasks(group) {
|
|
153
|
+
const rows = await this.#claim(TRANSPORT_TABLES.tasks, group);
|
|
154
|
+
for (const row of rows) {
|
|
155
|
+
const task = {
|
|
156
|
+
runId: row.run_id,
|
|
157
|
+
seq: Number(row.seq),
|
|
158
|
+
stepId: row.step_id,
|
|
159
|
+
name: row.name,
|
|
160
|
+
group,
|
|
161
|
+
input: fromJson(row.input),
|
|
162
|
+
attempt: Number(row.attempt),
|
|
163
|
+
...(row.traceparent != null ? { traceparent: row.traceparent } : {}),
|
|
164
|
+
...(row.context != null ? { context: fromJson(row.context) } : {}),
|
|
165
|
+
...(row.transport != null ? { transport: row.transport } : {}),
|
|
166
|
+
};
|
|
167
|
+
const result = await runStepHandler(task, this.#handlers.get(task.name));
|
|
168
|
+
await this.#insertResult(result);
|
|
169
|
+
await this.#client().from(TRANSPORT_TABLES.tasks).where('step_id', task.stepId).delete();
|
|
170
|
+
}
|
|
171
|
+
return rows.length;
|
|
172
|
+
}
|
|
173
|
+
async #insertResult(result) {
|
|
174
|
+
await this.#client()
|
|
175
|
+
.insertQuery()
|
|
176
|
+
.table(TRANSPORT_TABLES.results)
|
|
177
|
+
.knexQuery.insert({
|
|
178
|
+
step_id: result.stepId,
|
|
179
|
+
run_id: result.runId,
|
|
180
|
+
seq: result.seq,
|
|
181
|
+
status: result.status,
|
|
182
|
+
output: toJson(result.output),
|
|
183
|
+
error: toJson(result.error),
|
|
184
|
+
started_at: result.startedAt ?? null,
|
|
185
|
+
events: toJson(result.events),
|
|
186
|
+
claimed_by: null,
|
|
187
|
+
claimed_at: null,
|
|
188
|
+
created_at: this.#now(),
|
|
189
|
+
})
|
|
190
|
+
.onConflict('step_id')
|
|
191
|
+
.ignore();
|
|
192
|
+
}
|
|
193
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
194
|
+
// worker → engine — the engine polls results + heartbeats
|
|
195
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
196
|
+
onResult(handler) {
|
|
197
|
+
this.#pollers.start(async () => (await this.#drainResults(handler)) > 0);
|
|
198
|
+
}
|
|
199
|
+
onHeartbeat(handler) {
|
|
200
|
+
this.#pollers.start(async () => (await this.#drainHeartbeats(handler)) > 0);
|
|
201
|
+
}
|
|
202
|
+
async #drainResults(handler) {
|
|
203
|
+
const rows = await this.#claim(TRANSPORT_TABLES.results);
|
|
204
|
+
for (const row of rows) {
|
|
205
|
+
const result = {
|
|
206
|
+
runId: row.run_id,
|
|
207
|
+
seq: Number(row.seq),
|
|
208
|
+
stepId: row.step_id,
|
|
209
|
+
status: row.status,
|
|
210
|
+
output: fromJson(row.output),
|
|
211
|
+
error: fromJson(row.error),
|
|
212
|
+
startedAt: row.started_at == null ? undefined : Number(row.started_at),
|
|
213
|
+
events: fromJson(row.events),
|
|
214
|
+
};
|
|
215
|
+
await handler(result);
|
|
216
|
+
await this.#client().from(TRANSPORT_TABLES.results).where('step_id', result.stepId).delete();
|
|
217
|
+
}
|
|
218
|
+
return rows.length;
|
|
219
|
+
}
|
|
220
|
+
async #drainHeartbeats(handler) {
|
|
221
|
+
const rows = await this.#claim(TRANSPORT_TABLES.heartbeats, undefined, 'id');
|
|
222
|
+
for (const row of rows) {
|
|
223
|
+
await handler({
|
|
224
|
+
runId: row.run_id,
|
|
225
|
+
seq: Number(row.seq),
|
|
226
|
+
stepId: row.step_id,
|
|
227
|
+
group: row.grp,
|
|
228
|
+
});
|
|
229
|
+
await this.#client().from(TRANSPORT_TABLES.heartbeats).where('id', row.id).delete();
|
|
230
|
+
}
|
|
231
|
+
return rows.length;
|
|
232
|
+
}
|
|
233
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
234
|
+
// control plane (best-effort, single-consumer)
|
|
235
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
236
|
+
async publishControl(msg) {
|
|
237
|
+
await this.#ensureSchema();
|
|
238
|
+
const stamped = msg.from ? msg : { ...msg, from: this.#instanceId };
|
|
239
|
+
await this.#client()
|
|
240
|
+
.table(TRANSPORT_TABLES.control)
|
|
241
|
+
.insert({
|
|
242
|
+
payload: JSON.stringify(stamped),
|
|
243
|
+
claimed_by: null,
|
|
244
|
+
claimed_at: null,
|
|
245
|
+
created_at: this.#now(),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
onControl(handler) {
|
|
249
|
+
this.#pollers.start(async () => (await this.#drainControl(handler)) > 0);
|
|
250
|
+
}
|
|
251
|
+
async #drainControl(handler) {
|
|
252
|
+
const rows = await this.#claim(TRANSPORT_TABLES.control, undefined, 'id');
|
|
253
|
+
for (const row of rows) {
|
|
254
|
+
const msg = fromJson(row.payload);
|
|
255
|
+
if (msg)
|
|
256
|
+
handler(msg);
|
|
257
|
+
await this.#client().from(TRANSPORT_TABLES.control).where('id', row.id).delete();
|
|
258
|
+
}
|
|
259
|
+
return rows.length;
|
|
260
|
+
}
|
|
261
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
262
|
+
// atomic claim — portable compare-and-set (no FOR UPDATE SKIP LOCKED)
|
|
263
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
264
|
+
/**
|
|
265
|
+
* Atomically claim up to `batchSize` un-leased rows (optionally narrowed by `where`) and stamp them
|
|
266
|
+
* with this instance's id + a fresh per-round claim timestamp, then SELECT exactly the rows this
|
|
267
|
+
* round stamped. The single conditional `UPDATE … WHERE claimed_at IS NULL OR claimed_at < stale`
|
|
268
|
+
* is the concurrency guard: two instances racing the same rows can't both stamp them (the loser's
|
|
269
|
+
* UPDATE matches nothing for those rows). A crashed claimer's rows are reclaimed once their lease
|
|
270
|
+
* expires (`claimed_at < now - leaseMs`).
|
|
271
|
+
*
|
|
272
|
+
* `claimed_at` is set to a unique, strictly-increasing-per-round value so the SELECT-back is exact
|
|
273
|
+
* even when the same instance claims several rounds in quick succession.
|
|
274
|
+
*/
|
|
275
|
+
async #claim(table, group, idCol = 'step_id') {
|
|
276
|
+
await this.#ensureSchema();
|
|
277
|
+
// The raw Knex builder — `onConflict`, the `where(cb)` grouping and `whereIn` are cleaner there
|
|
278
|
+
// than through Lucid's stricter query-builder typings, and we only need plain SQL here.
|
|
279
|
+
const knex = this.#client().knexQuery();
|
|
280
|
+
const stale = this.#now() - this.#leaseMs;
|
|
281
|
+
// Unique claim token for THIS round: instance id + a nanosecond stamp. Stored in `claimed_by` so
|
|
282
|
+
// the SELECT-back returns only the rows this exact round won (never another round's, even from
|
|
283
|
+
// the same instance).
|
|
284
|
+
const token = `${this.#instanceId}:${process.hrtime.bigint().toString(36)}`;
|
|
285
|
+
const at = this.#now();
|
|
286
|
+
// 1) Pick candidate ids (unclaimed or stale-lease), oldest first, bounded by batchSize.
|
|
287
|
+
const candidates = (await knex
|
|
288
|
+
.from(table)
|
|
289
|
+
.select(idCol)
|
|
290
|
+
.modify((q) => {
|
|
291
|
+
if (group !== undefined)
|
|
292
|
+
q.where('grp', group);
|
|
293
|
+
})
|
|
294
|
+
.where((q) => q.whereNull('claimed_at').orWhere('claimed_at', '<', stale))
|
|
295
|
+
.orderBy(idCol === 'id' ? 'id' : 'created_at', 'asc')
|
|
296
|
+
.limit(this.#batchSize));
|
|
297
|
+
if (candidates.length === 0)
|
|
298
|
+
return [];
|
|
299
|
+
const ids = candidates.map((c) => c[idCol]);
|
|
300
|
+
// 2) Conditionally claim them — only rows STILL un-leased flip to this round's token. A racing
|
|
301
|
+
// instance's UPDATE matches nothing for the rows it lost, so no row is claimed twice.
|
|
302
|
+
await this.#client()
|
|
303
|
+
.knexQuery()
|
|
304
|
+
.from(table)
|
|
305
|
+
.whereIn(idCol, ids)
|
|
306
|
+
.where((q) => q.whereNull('claimed_at').orWhere('claimed_at', '<', stale))
|
|
307
|
+
.update({ claimed_by: token, claimed_at: at });
|
|
308
|
+
// 3) SELECT back exactly the rows this round won.
|
|
309
|
+
const rows = (await this.#client()
|
|
310
|
+
.knexQuery()
|
|
311
|
+
.from(table)
|
|
312
|
+
.select('*')
|
|
313
|
+
.where('claimed_by', token)
|
|
314
|
+
.where('claimed_at', at));
|
|
315
|
+
return rows;
|
|
316
|
+
}
|
|
317
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
318
|
+
// poll loop lifecycle (the recursive-timer / drain-burst / stop-all bookkeeping
|
|
319
|
+
// lives in core's Pollers; here each loop is just a `drain* > 0` tick)
|
|
320
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
321
|
+
/**
|
|
322
|
+
* No-op convenience: the loops auto-start when `onResult`/`onHeartbeat`/`onControl`/`handle` are
|
|
323
|
+
* registered. Exposed for symmetry and to mirror broker transports — call it after wiring handlers
|
|
324
|
+
* if you prefer an explicit start. Returns once the schema is ready.
|
|
325
|
+
*/
|
|
326
|
+
async start() {
|
|
327
|
+
this.#pollers.reopen();
|
|
328
|
+
await this.#ensureSchema();
|
|
329
|
+
}
|
|
330
|
+
/** Stop every poll loop. Does not close the shared `Database`. */
|
|
331
|
+
async stop() {
|
|
332
|
+
this.#pollers.stopAll();
|
|
333
|
+
this.#taskLoop = undefined;
|
|
334
|
+
}
|
|
335
|
+
/** Stop the pollers (alias of {@link stop} for the `Transport.close` contract). */
|
|
336
|
+
async close() {
|
|
337
|
+
await this.stop();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/transports/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AdapterFactory } from '@adonisjs/queue/types';
|
|
2
|
+
import type { ControlPlane, Transport } from '../interfaces.js';
|
|
3
|
+
/**
|
|
4
|
+
* The minimal application surface a {@link TransportFactory} thunk needs at boot to resolve an
|
|
5
|
+
* optional peer's service (the Lucid `db`, the queue adapter, etc.). The durable provider passes the
|
|
6
|
+
* booted `ApplicationService`, which satisfies this structurally — typed here so core stays free of a
|
|
7
|
+
* hard `@adonisjs/core` dependency.
|
|
8
|
+
*/
|
|
9
|
+
export interface TransportContext {
|
|
10
|
+
/** The booted application — used to resolve services/connections from the container. */
|
|
11
|
+
app: {
|
|
12
|
+
container: {
|
|
13
|
+
make(service: unknown): Promise<unknown>;
|
|
14
|
+
};
|
|
15
|
+
config: {
|
|
16
|
+
get<T>(key: string, defaultValue?: T): T;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A configured transport: a thunk the durable provider calls at boot to build the {@link Transport}
|
|
22
|
+
* (often also a {@link ControlPlane}). Each factory lazily imports its peer dependency
|
|
23
|
+
* (`@adonisjs/queue`, `@adonisjs/lucid`) inside the thunk, so the driver is only loaded when it is
|
|
24
|
+
* actually selected — keeping those packages optional.
|
|
25
|
+
*/
|
|
26
|
+
export type TransportFactory = (ctx: TransportContext) => Promise<Transport & Partial<ControlPlane>>;
|
|
27
|
+
/** Options for the in-memory transport (no peer dependency). */
|
|
28
|
+
export interface MemoryTransportConfig {
|
|
29
|
+
}
|
|
30
|
+
/** Options for the `@adonisjs/queue` transport. */
|
|
31
|
+
export interface QueueTransportConfig {
|
|
32
|
+
/**
|
|
33
|
+
* Name of the `@adonisjs/queue` connection — a key of the `adapters` map in `config/queue.ts` —
|
|
34
|
+
* whose adapter this transport reads/writes. Omit to use that file's `default` connection. You
|
|
35
|
+
* configure the driver and its host/credentials once in `config/queue.ts`; durable just references
|
|
36
|
+
* it by name, exactly like `stores.lucid({ connection })` or `stores.redis({ connection })`.
|
|
37
|
+
*/
|
|
38
|
+
connection?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Escape hatch: pass a raw `@adonisjs/queue` adapter factory directly (e.g. `redis(...)`) instead of
|
|
41
|
+
* resolving one from `config/queue.ts`. For non-Adonis setups or a bespoke adapter. Takes
|
|
42
|
+
* precedence over `connection`.
|
|
43
|
+
*/
|
|
44
|
+
adapter?: AdapterFactory;
|
|
45
|
+
/** Worker group this instance serves (required on a worker process to register handlers). */
|
|
46
|
+
group?: string;
|
|
47
|
+
/** Queue-name prefix so several apps can share one backend without colliding. Default `durable`. */
|
|
48
|
+
prefix?: string;
|
|
49
|
+
/** Poll interval (ms) for the result/task/heartbeat/control loops. Default 200ms. */
|
|
50
|
+
pollIntervalMs?: number;
|
|
51
|
+
/** Stable id for this process (stamped on heartbeats / control `from`). Default a random id. */
|
|
52
|
+
instanceId?: string;
|
|
53
|
+
}
|
|
54
|
+
/** Options for the DB-table-backed (`@adonisjs/lucid`) transport. */
|
|
55
|
+
export interface DbTransportConfig {
|
|
56
|
+
/** Worker group this instance serves (required on a worker process to register handlers). */
|
|
57
|
+
group?: string;
|
|
58
|
+
/** Lucid connection name to use. Defaults to the `Database` default connection. */
|
|
59
|
+
connection?: string;
|
|
60
|
+
/** Poll interval (ms) for the result/task/heartbeat/control loops. Default 200ms. */
|
|
61
|
+
pollIntervalMs?: number;
|
|
62
|
+
/** How long a claimed-but-unfinished row is owned before it's reclaimable (crash recovery). Default 30s. */
|
|
63
|
+
leaseMs?: number;
|
|
64
|
+
/** Max rows claimed per poll. Default 20. */
|
|
65
|
+
batchSize?: number;
|
|
66
|
+
/** Create the transport tables on first use if missing. Default true. */
|
|
67
|
+
autoCreate?: boolean;
|
|
68
|
+
/** Stable id for this process (stamped on heartbeats / control `from` / `claimed_by`). Default random. */
|
|
69
|
+
instanceId?: string;
|
|
70
|
+
}
|
|
71
|
+
export declare const transports: {
|
|
72
|
+
/** In-process transport + control plane (single-process, no extra infra). The default. */
|
|
73
|
+
memory(_config?: MemoryTransportConfig): TransportFactory;
|
|
74
|
+
/** Run remote steps cross-process over `@adonisjs/queue`, using a connection from `config/queue.ts`. */
|
|
75
|
+
queue(config?: QueueTransportConfig): TransportFactory;
|
|
76
|
+
/** Run remote steps cross-process over the app's database, using `@adonisjs/lucid` — no broker. */
|
|
77
|
+
db(config?: DbTransportConfig): TransportFactory;
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/transports/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGhE;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wFAAwF;IACxF,GAAG,EAAE;QACH,SAAS,EAAE;YAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;SAAE,CAAC;QACxD,MAAM,EAAE;YAAE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;SAAE,CAAC;KACtD,CAAC;CACH;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;AAEhD,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;CAErC;AAED,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oGAAoG;IACpG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,6FAA6F;IAC7F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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;AAyDD,eAAO,MAAM,UAAU;IACrB,0FAA0F;qBAC1E,qBAAqB,GAAQ,gBAAgB;IAI7D,wGAAwG;mBAC1F,oBAAoB,GAAQ,gBAAgB;IAc1D,mGAAmG;gBACxF,iBAAiB,GAAQ,gBAAgB;CAgBrD,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { InMemoryTransport } from '../testing/in-memory-transport.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a raw `@adonisjs/queue` adapter factory from `config/queue.ts` by connection name —
|
|
4
|
+
* mirroring `@adonisjs/queue`'s own `resolveAdapters`: a function entry is the factory; a config
|
|
5
|
+
* provider is resolved via its `resolver(app)`. Reads only the app config, so it pulls in no
|
|
6
|
+
* `@adonisjs/queue` runtime code.
|
|
7
|
+
*/
|
|
8
|
+
async function resolveQueueAdapter(ctx, connection) {
|
|
9
|
+
const queueConfig = ctx.app.config.get('queue', { adapters: {} });
|
|
10
|
+
const name = connection ?? queueConfig.default;
|
|
11
|
+
if (!name) {
|
|
12
|
+
throw new Error('@agora/durable: transports.queue() needs a `connection`, or a `default` in config/queue.ts');
|
|
13
|
+
}
|
|
14
|
+
const entry = queueConfig.adapters?.[name];
|
|
15
|
+
if (!entry) {
|
|
16
|
+
throw new Error(`@agora/durable: unknown @adonisjs/queue connection "${name}" — check the adapters in config/queue.ts`);
|
|
17
|
+
}
|
|
18
|
+
return typeof entry === 'function' ? entry : entry.resolver(ctx.app);
|
|
19
|
+
}
|
|
20
|
+
export const transports = {
|
|
21
|
+
/** In-process transport + control plane (single-process, no extra infra). The default. */
|
|
22
|
+
memory(_config = {}) {
|
|
23
|
+
return async () => new InMemoryTransport();
|
|
24
|
+
},
|
|
25
|
+
/** Run remote steps cross-process over `@adonisjs/queue`, using a connection from `config/queue.ts`. */
|
|
26
|
+
queue(config = {}) {
|
|
27
|
+
return async (ctx) => {
|
|
28
|
+
const { QueueTransport } = await import('./queue.js');
|
|
29
|
+
const adapter = config.adapter ?? (await resolveQueueAdapter(ctx, config.connection));
|
|
30
|
+
return new QueueTransport({
|
|
31
|
+
adapter,
|
|
32
|
+
...(config.group !== undefined ? { group: config.group } : {}),
|
|
33
|
+
...(config.prefix !== undefined ? { prefix: config.prefix } : {}),
|
|
34
|
+
...(config.pollIntervalMs !== undefined ? { pollIntervalMs: config.pollIntervalMs } : {}),
|
|
35
|
+
...(config.instanceId !== undefined ? { instanceId: config.instanceId } : {}),
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
/** Run remote steps cross-process over the app's database, using `@adonisjs/lucid` — no broker. */
|
|
40
|
+
db(config = {}) {
|
|
41
|
+
return async () => {
|
|
42
|
+
const db = (await import('@adonisjs/lucid/services/db')).default;
|
|
43
|
+
const { DbTransport } = await import('./db.js');
|
|
44
|
+
return new DbTransport({
|
|
45
|
+
db,
|
|
46
|
+
...(config.group !== undefined ? { group: config.group } : {}),
|
|
47
|
+
...(config.connection !== undefined ? { connectionName: config.connection } : {}),
|
|
48
|
+
...(config.pollIntervalMs !== undefined ? { pollIntervalMs: config.pollIntervalMs } : {}),
|
|
49
|
+
...(config.leaseMs !== undefined ? { leaseMs: config.leaseMs } : {}),
|
|
50
|
+
...(config.batchSize !== undefined ? { batchSize: config.batchSize } : {}),
|
|
51
|
+
...(config.autoCreate !== undefined ? { autoCreate: config.autoCreate } : {}),
|
|
52
|
+
...(config.instanceId !== undefined ? { instanceId: config.instanceId } : {}),
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/transports/factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AcquiredJob, Adapter, JobData } from '@adonisjs/queue/types';
|
|
2
|
+
/**
|
|
3
|
+
* A tiny in-memory `@adonisjs/queue` adapter for tests — implements just the surface the
|
|
4
|
+
* `QueueTransport` touches (push/pop/complete/fail/destroy) as plain FIFO queues, plus throwing
|
|
5
|
+
* stubs for the rest of the contract. No Redis, no Knex. `popFrom` mimics the real adapters'
|
|
6
|
+
* atomic move (pending → active) so two transports sharing one instance never double-consume.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MockAdapter implements Adapter {
|
|
9
|
+
#private;
|
|
10
|
+
readonly pending: Map<string, JobData[]>;
|
|
11
|
+
readonly active: Map<string, AcquiredJob>;
|
|
12
|
+
workerId: string;
|
|
13
|
+
destroyed: boolean;
|
|
14
|
+
setWorkerId(id: string): void;
|
|
15
|
+
pushOn(queue: string, jobData: JobData): Promise<void>;
|
|
16
|
+
push(jobData: JobData): Promise<void>;
|
|
17
|
+
popFrom(queue: string): Promise<AcquiredJob | null>;
|
|
18
|
+
pop(): Promise<AcquiredJob | null>;
|
|
19
|
+
completeJob(jobId: string): Promise<void>;
|
|
20
|
+
failJob(jobId: string): Promise<void>;
|
|
21
|
+
sizeOf(queue: string): Promise<number>;
|
|
22
|
+
size(): Promise<number>;
|
|
23
|
+
destroy(): Promise<void>;
|
|
24
|
+
pushLater: () => Promise<never>;
|
|
25
|
+
pushLaterOn: () => Promise<never>;
|
|
26
|
+
pushMany: () => Promise<never>;
|
|
27
|
+
pushManyOn: () => Promise<never>;
|
|
28
|
+
recoverStalledJobs: () => Promise<never>;
|
|
29
|
+
retryJob: () => Promise<never>;
|
|
30
|
+
getJob: () => Promise<never>;
|
|
31
|
+
upsertSchedule: () => Promise<never>;
|
|
32
|
+
createSchedule: () => Promise<never>;
|
|
33
|
+
getSchedule: () => Promise<never>;
|
|
34
|
+
listSchedules: () => Promise<never>;
|
|
35
|
+
updateSchedule: () => Promise<never>;
|
|
36
|
+
deleteSchedule: () => Promise<never>;
|
|
37
|
+
claimDueSchedule: () => Promise<never>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=queue-mock-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-mock-adapter.d.ts","sourceRoot":"","sources":["../../../src/transports/queue-mock-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAE3E;;;;;GAKG;AACH,qBAAa,WAAY,YAAW,OAAO;;IACzC,QAAQ,CAAC,OAAO,yBAAgC;IAChD,QAAQ,CAAC,MAAM,2BAAkC;IACjD,QAAQ,SAAM;IACd,SAAS,UAAS;IAElB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIvB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtD,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAsBnD,GAAG,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIlC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAItC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,SAAS,QAgBU,OAAO,CAAC,KAAK,CAAC,CAhBU;IAC3C,WAAW,QAeQ,OAAO,CAAC,KAAK,CAAC,CAfc;IAC/C,QAAQ,QAcW,OAAO,CAAC,KAAK,CAAC,CAdQ;IACzC,UAAU,QAaS,OAAO,CAAC,KAAK,CAAC,CAbY;IAC7C,kBAAkB,QAYC,OAAO,CAAC,KAAK,CAAC,CAZ4B;IAC7D,QAAQ,QAWW,OAAO,CAAC,KAAK,CAAC,CAXQ;IACzC,MAAM,QAUa,OAAO,CAAC,KAAK,CAAC,CAVI;IACrC,cAAc,QASK,OAAO,CAAC,KAAK,CAAC,CAToB;IACrD,cAAc,QAQK,OAAO,CAAC,KAAK,CAAC,CARoB;IACrD,WAAW,QAOQ,OAAO,CAAC,KAAK,CAAC,CAPc;IAC/C,aAAa,QAMM,OAAO,CAAC,KAAK,CAAC,CANkB;IACnD,cAAc,QAKK,OAAO,CAAC,KAAK,CAAC,CALoB;IACrD,cAAc,QAIK,OAAO,CAAC,KAAK,CAAC,CAJoB;IACrD,gBAAgB,QAGG,OAAO,CAAC,KAAK,CAAC,CAHwB;CAQ1D"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny in-memory `@adonisjs/queue` adapter for tests — implements just the surface the
|
|
3
|
+
* `QueueTransport` touches (push/pop/complete/fail/destroy) as plain FIFO queues, plus throwing
|
|
4
|
+
* stubs for the rest of the contract. No Redis, no Knex. `popFrom` mimics the real adapters'
|
|
5
|
+
* atomic move (pending → active) so two transports sharing one instance never double-consume.
|
|
6
|
+
*/
|
|
7
|
+
export class MockAdapter {
|
|
8
|
+
pending = new Map();
|
|
9
|
+
active = new Map();
|
|
10
|
+
workerId = '';
|
|
11
|
+
destroyed = false;
|
|
12
|
+
setWorkerId(id) {
|
|
13
|
+
this.workerId = id;
|
|
14
|
+
}
|
|
15
|
+
async pushOn(queue, jobData) {
|
|
16
|
+
const list = this.pending.get(queue) ?? [];
|
|
17
|
+
list.push(jobData);
|
|
18
|
+
this.pending.set(queue, list);
|
|
19
|
+
}
|
|
20
|
+
async push(jobData) {
|
|
21
|
+
await this.pushOn('default', jobData);
|
|
22
|
+
}
|
|
23
|
+
async popFrom(queue) {
|
|
24
|
+
const list = this.pending.get(queue);
|
|
25
|
+
if (!list || list.length === 0)
|
|
26
|
+
return null;
|
|
27
|
+
// Mirror the real adapters' priority ordering: lower `priority` number runs first (default 5 when
|
|
28
|
+
// absent), FIFO among equal priorities. A plain FIFO queue (no priorities set) is unchanged.
|
|
29
|
+
const DEFAULT_PRIORITY = 5;
|
|
30
|
+
let bestIndex = 0;
|
|
31
|
+
let bestPriority = list[0]?.priority ?? DEFAULT_PRIORITY;
|
|
32
|
+
for (let i = 1; i < list.length; i += 1) {
|
|
33
|
+
const candidate = list[i]?.priority ?? DEFAULT_PRIORITY;
|
|
34
|
+
if (candidate < bestPriority) {
|
|
35
|
+
bestIndex = i;
|
|
36
|
+
bestPriority = candidate;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const [job] = list.splice(bestIndex, 1);
|
|
40
|
+
if (!job)
|
|
41
|
+
return null;
|
|
42
|
+
const acquired = { ...job, acquiredAt: Date.now() };
|
|
43
|
+
this.active.set(job.id, acquired);
|
|
44
|
+
return acquired;
|
|
45
|
+
}
|
|
46
|
+
async pop() {
|
|
47
|
+
return this.popFrom('default');
|
|
48
|
+
}
|
|
49
|
+
async completeJob(jobId) {
|
|
50
|
+
this.active.delete(jobId);
|
|
51
|
+
}
|
|
52
|
+
async failJob(jobId) {
|
|
53
|
+
this.active.delete(jobId);
|
|
54
|
+
}
|
|
55
|
+
async sizeOf(queue) {
|
|
56
|
+
return this.pending.get(queue)?.length ?? 0;
|
|
57
|
+
}
|
|
58
|
+
async size() {
|
|
59
|
+
return this.sizeOf('default');
|
|
60
|
+
}
|
|
61
|
+
async destroy() {
|
|
62
|
+
this.destroyed = true;
|
|
63
|
+
}
|
|
64
|
+
// --- Unused by the transport: present only to satisfy the Adapter contract. ---
|
|
65
|
+
/* c8 ignore start */
|
|
66
|
+
pushLater = this.#unsupported('pushLater');
|
|
67
|
+
pushLaterOn = this.#unsupported('pushLaterOn');
|
|
68
|
+
pushMany = this.#unsupported('pushMany');
|
|
69
|
+
pushManyOn = this.#unsupported('pushManyOn');
|
|
70
|
+
recoverStalledJobs = this.#unsupported('recoverStalledJobs');
|
|
71
|
+
retryJob = this.#unsupported('retryJob');
|
|
72
|
+
getJob = this.#unsupported('getJob');
|
|
73
|
+
upsertSchedule = this.#unsupported('upsertSchedule');
|
|
74
|
+
createSchedule = this.#unsupported('createSchedule');
|
|
75
|
+
getSchedule = this.#unsupported('getSchedule');
|
|
76
|
+
listSchedules = this.#unsupported('listSchedules');
|
|
77
|
+
updateSchedule = this.#unsupported('updateSchedule');
|
|
78
|
+
deleteSchedule = this.#unsupported('deleteSchedule');
|
|
79
|
+
claimDueSchedule = this.#unsupported('claimDueSchedule');
|
|
80
|
+
#unsupported(name) {
|
|
81
|
+
return async () => {
|
|
82
|
+
throw new Error(`MockAdapter.${name} is not implemented`);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=queue-mock-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-mock-adapter.js","sourceRoot":"","sources":["../../../src/transports/queue-mock-adapter.ts"],"names":[],"mappings":"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"}
|