@adonis-agora/durable 0.10.0 → 0.11.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/CHANGELOG.md +6 -0
- package/dist/assets/dashboard.html +116 -3
- package/dist/commands/durable_worker.d.ts +25 -0
- package/dist/commands/durable_worker.d.ts.map +1 -0
- package/dist/commands/durable_worker.js +113 -0
- package/dist/commands/durable_worker.js.map +1 -0
- package/dist/commands/main.d.ts +6 -5
- package/dist/commands/main.d.ts.map +1 -1
- package/dist/commands/main.js +11 -4
- package/dist/commands/main.js.map +1 -1
- package/dist/providers/dashboard_provider.d.ts +37 -0
- package/dist/providers/dashboard_provider.d.ts.map +1 -1
- package/dist/providers/dashboard_provider.js +98 -9
- package/dist/providers/dashboard_provider.js.map +1 -1
- package/dist/providers/durable_provider.d.ts +24 -16
- package/dist/providers/durable_provider.d.ts.map +1 -1
- package/dist/providers/durable_provider.js +195 -20
- package/dist/providers/durable_provider.js.map +1 -1
- package/dist/src/config_types.d.ts +92 -0
- package/dist/src/config_types.d.ts.map +1 -0
- package/dist/src/config_types.js +2 -0
- package/dist/src/config_types.js.map +1 -0
- package/dist/src/dashboard/compat-view.d.ts +13 -0
- package/dist/src/dashboard/compat-view.d.ts.map +1 -0
- package/dist/src/dashboard/compat-view.js +32 -0
- package/dist/src/dashboard/compat-view.js.map +1 -0
- package/dist/src/dashboard/compat.d.ts +76 -0
- package/dist/src/dashboard/compat.d.ts.map +1 -0
- package/dist/src/dashboard/compat.js +130 -0
- package/dist/src/dashboard/compat.js.map +1 -0
- package/dist/src/dashboard/diagnostics-recorder.d.ts +59 -0
- package/dist/src/dashboard/diagnostics-recorder.d.ts.map +1 -0
- package/dist/src/dashboard/diagnostics-recorder.js +75 -0
- package/dist/src/dashboard/diagnostics-recorder.js.map +1 -0
- package/dist/src/dashboard/gateway-adapter.d.ts +37 -0
- package/dist/src/dashboard/gateway-adapter.d.ts.map +1 -0
- package/dist/src/dashboard/gateway-adapter.js +49 -0
- package/dist/src/dashboard/gateway-adapter.js.map +1 -0
- package/dist/src/dashboard/handlers.d.ts +31 -8
- package/dist/src/dashboard/handlers.d.ts.map +1 -1
- package/dist/src/dashboard/handlers.js +2 -1
- package/dist/src/dashboard/handlers.js.map +1 -1
- package/dist/src/dashboard/index.d.ts +10 -3
- package/dist/src/dashboard/index.d.ts.map +1 -1
- package/dist/src/dashboard/index.js +8 -2
- package/dist/src/dashboard/index.js.map +1 -1
- package/dist/src/define_config.d.ts +31 -5
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js +4 -3
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/dispatch-routing.d.ts +105 -0
- package/dist/src/dispatch-routing.d.ts.map +1 -0
- package/dist/src/dispatch-routing.js +114 -0
- package/dist/src/dispatch-routing.js.map +1 -0
- package/dist/src/engine.d.ts +65 -2
- package/dist/src/engine.d.ts.map +1 -1
- package/dist/src/engine.js +131 -3
- package/dist/src/engine.js.map +1 -1
- package/dist/src/handshake/descriptor.d.ts +128 -0
- package/dist/src/handshake/descriptor.d.ts.map +1 -0
- package/dist/src/handshake/descriptor.js +133 -0
- package/dist/src/handshake/descriptor.js.map +1 -0
- package/dist/src/handshake/negotiate.d.ts +83 -0
- package/dist/src/handshake/negotiate.d.ts.map +1 -0
- package/dist/src/handshake/negotiate.js +108 -0
- package/dist/src/handshake/negotiate.js.map +1 -0
- package/dist/src/handshake/routing.d.ts +51 -0
- package/dist/src/handshake/routing.d.ts.map +1 -0
- package/dist/src/handshake/routing.js +57 -0
- package/dist/src/handshake/routing.js.map +1 -0
- package/dist/src/index.d.ts +14 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces.d.ts +168 -2
- package/dist/src/interfaces.d.ts.map +1 -1
- package/dist/src/remote-workflow-executor.d.ts +25 -1
- package/dist/src/remote-workflow-executor.d.ts.map +1 -1
- package/dist/src/remote-workflow-executor.js +41 -0
- package/dist/src/remote-workflow-executor.js.map +1 -1
- package/dist/src/role_bindings.d.ts +85 -0
- package/dist/src/role_bindings.d.ts.map +1 -0
- package/dist/src/role_bindings.js +73 -0
- package/dist/src/role_bindings.js.map +1 -0
- package/dist/src/run-gateway/interface.d.ts +89 -0
- package/dist/src/run-gateway/interface.d.ts.map +1 -0
- package/dist/src/run-gateway/interface.js +2 -0
- package/dist/src/run-gateway/interface.js.map +1 -0
- package/dist/src/run-gateway/proxy-run-gateway.d.ts +84 -0
- package/dist/src/run-gateway/proxy-run-gateway.d.ts.map +1 -0
- package/dist/src/run-gateway/proxy-run-gateway.js +142 -0
- package/dist/src/run-gateway/proxy-run-gateway.js.map +1 -0
- package/dist/src/run-gateway/run-request-responder.d.ts +67 -0
- package/dist/src/run-gateway/run-request-responder.d.ts.map +1 -0
- package/dist/src/run-gateway/run-request-responder.js +228 -0
- package/dist/src/run-gateway/run-request-responder.js.map +1 -0
- package/dist/src/run-gateway/store-run-gateway.d.ts +90 -0
- package/dist/src/run-gateway/store-run-gateway.d.ts.map +1 -0
- package/dist/src/run-gateway/store-run-gateway.js +80 -0
- package/dist/src/run-gateway/store-run-gateway.js.map +1 -0
- package/dist/src/run-gateway/tenant-auth.d.ts +19 -0
- package/dist/src/run-gateway/tenant-auth.d.ts.map +1 -0
- package/dist/src/run-gateway/tenant-auth.js +71 -0
- package/dist/src/run-gateway/tenant-auth.js.map +1 -0
- package/dist/src/services/main.d.ts +16 -3
- package/dist/src/services/main.d.ts.map +1 -1
- package/dist/src/services/main.js +23 -4
- package/dist/src/services/main.js.map +1 -1
- package/dist/src/step-name-symbol.d.ts +3 -0
- package/dist/src/step-name-symbol.d.ts.map +1 -1
- package/dist/src/step-name-symbol.js.map +1 -1
- package/dist/src/step-ref.d.ts +4 -0
- package/dist/src/step-ref.d.ts.map +1 -1
- package/dist/src/step-ref.js +2 -0
- package/dist/src/step-ref.js.map +1 -1
- package/dist/src/transports/bullmq/bullmq-transport.d.ts +130 -0
- package/dist/src/transports/bullmq/bullmq-transport.d.ts.map +1 -0
- package/dist/src/transports/bullmq/bullmq-transport.js +562 -0
- package/dist/src/transports/bullmq/bullmq-transport.js.map +1 -0
- package/dist/src/transports/bullmq/deps.d.ts +59 -0
- package/dist/src/transports/bullmq/deps.d.ts.map +1 -0
- package/dist/src/transports/bullmq/deps.js +41 -0
- package/dist/src/transports/bullmq/deps.js.map +1 -0
- package/dist/src/transports/bullmq/index.d.ts +5 -0
- package/dist/src/transports/bullmq/index.d.ts.map +1 -0
- package/dist/src/transports/bullmq/index.js +5 -0
- package/dist/src/transports/bullmq/index.js.map +1 -0
- package/dist/src/transports/bullmq/naming.d.ts +71 -0
- package/dist/src/transports/bullmq/naming.d.ts.map +1 -0
- package/dist/src/transports/bullmq/naming.js +101 -0
- package/dist/src/transports/bullmq/naming.js.map +1 -0
- package/dist/src/transports/bullmq/serialization.d.ts +56 -0
- package/dist/src/transports/bullmq/serialization.d.ts.map +1 -0
- package/dist/src/transports/bullmq/serialization.js +101 -0
- package/dist/src/transports/bullmq/serialization.js.map +1 -0
- package/dist/src/transports/factory.d.ts +31 -0
- package/dist/src/transports/factory.d.ts.map +1 -1
- package/dist/src/transports/factory.js +21 -0
- package/dist/src/transports/factory.js.map +1 -1
- package/dist/src/worker-runtime/index.d.ts +22 -0
- package/dist/src/worker-runtime/index.d.ts.map +1 -0
- package/dist/src/worker-runtime/index.js +27 -0
- package/dist/src/worker-runtime/index.js.map +1 -0
- package/dist/src/worker-runtime/naming.d.ts +24 -0
- package/dist/src/worker-runtime/naming.d.ts.map +1 -0
- package/dist/src/worker-runtime/naming.js +28 -0
- package/dist/src/worker-runtime/naming.js.map +1 -0
- package/dist/src/worker-runtime/registry.d.ts +81 -0
- package/dist/src/worker-runtime/registry.d.ts.map +1 -0
- package/dist/src/worker-runtime/registry.js +44 -0
- package/dist/src/worker-runtime/registry.js.map +1 -0
- package/dist/src/worker-runtime/worker-runtime.d.ts +155 -0
- package/dist/src/worker-runtime/worker-runtime.d.ts.map +1 -0
- package/dist/src/worker-runtime/worker-runtime.js +265 -0
- package/dist/src/worker-runtime/worker-runtime.js.map +1 -0
- package/dist/src/workflow-ctx.d.ts.map +1 -1
- package/dist/src/workflow-ctx.js +3 -0
- package/dist/src/workflow-ctx.js.map +1 -1
- package/dist/src/workflow-turn.d.ts +167 -0
- package/dist/src/workflow-turn.d.ts.map +1 -0
- package/dist/src/workflow-turn.js +372 -0
- package/dist/src/workflow-turn.js.map +1 -0
- package/package.json +7 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tiny broker surface the {@link import('./bullmq-transport.js').BullMQTransport} depends on, and
|
|
3
|
+
* the real-`bullmq` implementation of it. Splitting the concrete broker behind these structural
|
|
4
|
+
* interfaces is what keeps the transport itself PURE and unit-testable with fakes — and lets the
|
|
5
|
+
* package build/test without `bullmq` installed, since the only place that touches the real dependency
|
|
6
|
+
* is {@link createBullMQDeps}, which `import()`s it LAZILY (so a non-bullmq fleet never loads it).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Build the real bullmq/ioredis-backed {@link BullMQDeps} for `connection` (ioredis `ConnectionOptions`
|
|
10
|
+
* or a `Redis` instance) at a `concurrency`. `bullmq` and `ioredis` are imported LAZILY here — via a
|
|
11
|
+
* non-literal specifier so the package type-checks and unit-tests without them installed — and only
|
|
12
|
+
* this call (i.e. only when the transport is actually selected + run) pulls them in.
|
|
13
|
+
*
|
|
14
|
+
* Workers require `maxRetriesPerRequest: null`; a plain-options connection is cloned with it set (a
|
|
15
|
+
* passed-in `Redis` instance is preserved as-is). A standalone client for pub/sub / heartbeat keys is
|
|
16
|
+
* a `duplicate()` of a passed-in instance, or a fresh client with a keepalive floor from the options.
|
|
17
|
+
*/
|
|
18
|
+
export async function createBullMQDeps(connection, concurrency = 1) {
|
|
19
|
+
// Non-literal specifiers: keep `tsc` from resolving 'bullmq'/'ioredis' at build time (they are a
|
|
20
|
+
// runtime-only dependency of the selected transport), so the wider package builds without them.
|
|
21
|
+
const bullmqSpecifier = 'bullmq';
|
|
22
|
+
const ioredisSpecifier = 'ioredis';
|
|
23
|
+
const { Queue, Worker } = (await import(bullmqSpecifier));
|
|
24
|
+
const { Redis } = (await import(ioredisSpecifier));
|
|
25
|
+
const isRedisInstance = (value) => value instanceof Redis;
|
|
26
|
+
// Workers require `maxRetriesPerRequest: null`; preserve a passed-in Redis instance as-is.
|
|
27
|
+
const workerConnection = () => connection && typeof connection === 'object' && !('options' in connection)
|
|
28
|
+
? { ...connection, maxRetriesPerRequest: null }
|
|
29
|
+
: connection;
|
|
30
|
+
const makeRedis = () => {
|
|
31
|
+
if (isRedisInstance(connection))
|
|
32
|
+
return connection.duplicate();
|
|
33
|
+
return new Redis({ keepAlive: 10_000, ...connection });
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
makeQueue: (name) => new Queue(name, { connection }),
|
|
37
|
+
makeWorker: (name, process) => new Worker(name, (job) => process(job), { connection: workerConnection(), concurrency }),
|
|
38
|
+
makeRedis,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../../src/transports/bullmq/deps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgDH;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAmB,EAAE,WAAW,GAAG,CAAC;IACzE,iGAAiG;IACjG,gGAAgG;IAChG,MAAM,eAAe,GAAG,QAAQ,CAAC;IACjC,MAAM,gBAAgB,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAGvD,CAAC;IACF,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAEhD,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,KAAc,EAAmD,EAAE,CAC1F,KAAK,YAAa,KAA8D,CAAC;IAEnF,2FAA2F;IAC3F,MAAM,gBAAgB,GAAG,GAAY,EAAE,CACrC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,UAAU,CAAC;QACxE,CAAC,CAAC,EAAE,GAAI,UAAqB,EAAE,oBAAoB,EAAE,IAAI,EAAE;QAC3D,CAAC,CAAC,UAAU,CAAC;IAEjB,MAAM,SAAS,GAAG,GAAc,EAAE;QAChC,IAAI,eAAe,CAAC,UAAU,CAAC;YAAE,OAAO,UAAU,CAAC,SAAS,EAAE,CAAC;QAC/D,OAAO,IAAI,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAI,UAAqB,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC;QACpD,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAC5B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,CAAC;QAC1F,SAAS;KACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { BullMQTransport, type BullMQTransportOptions } from './bullmq-transport.js';
|
|
2
|
+
export { type BullMQDeps, type JobLike, type ProcessFn, type QueueLike, type RedisLike, type WorkerLike, createBullMQDeps, } from './deps.js';
|
|
3
|
+
export * from './naming.js';
|
|
4
|
+
export * from './serialization.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/transports/bullmq/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EACL,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/transports/bullmq/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA+B,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAOL,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { sanitizeQueueToken, tenantGroup } from '../../tenant-group.js';
|
|
2
|
+
/**
|
|
3
|
+
* Broker naming for the aviary-compatible BullMQ transport — the byte-for-byte queue / channel / key
|
|
4
|
+
* names a Python aviary worker (or a NestJS `BullMQTransport`) also computes, so a mixed-language
|
|
5
|
+
* fleet lands on the SAME Redis keys. Every name is derived here and NOWHERE else, so a single place
|
|
6
|
+
* owns the cross-SDK contract (see docs/superpowers/specs/2026-07-17-store-less-cluster-design.md §6.1).
|
|
7
|
+
*
|
|
8
|
+
* These are pure string builders (no Redis, no bullmq) so they unit-test in isolation and the wire
|
|
9
|
+
* naming can be proven byte-identical to the golden fixtures without a broker.
|
|
10
|
+
*/
|
|
11
|
+
/** Re-exported so a caller computing a routing token uses the exact same sanitize/suffix rules. */
|
|
12
|
+
export { sanitizeQueueToken, tenantGroup };
|
|
13
|
+
/**
|
|
14
|
+
* The prefix every name is built from, folding in the deployment namespace per the cross-SDK rule: a
|
|
15
|
+
* set, non-`"default"` namespace appends `-<namespace>`; an unset or `"default"` namespace yields the
|
|
16
|
+
* bare prefix (so the un-namespaced and `"default"` schemes are BYTE-IDENTICAL — production names
|
|
17
|
+
* never change). Keep ALL name builders routed through this; a single direct `prefix` concat would
|
|
18
|
+
* land a worker on a different queue than the engine and silently split the fleet.
|
|
19
|
+
*/
|
|
20
|
+
export declare function effectivePrefix(prefix: string, namespace: string | undefined): string;
|
|
21
|
+
/**
|
|
22
|
+
* The final routing token a step/workflow `name` dispatches to / a worker subscribes on:
|
|
23
|
+
* `tenantGroup(sanitizeQueueToken(name), partition)`. `:`→`-` (BullMQ forbids `:` in a queue name),
|
|
24
|
+
* `.` kept, and a non-empty/non-`default` partition suffixes `@<partition>`. Apply IDENTICALLY at
|
|
25
|
+
* dispatch and subscribe or a step routes to one token and is served from another (silently never run).
|
|
26
|
+
*/
|
|
27
|
+
export declare function routingToken(name: string, partition: string | undefined): string;
|
|
28
|
+
/** `${P}-tasks-${token}` — the per-routing-token task queue (jobs `task` / `workflow`). */
|
|
29
|
+
export declare function tasksName(effPrefix: string, token: string): string;
|
|
30
|
+
/** `${P}-results` — the shared step-result queue (job `result`). */
|
|
31
|
+
export declare function resultsName(effPrefix: string): string;
|
|
32
|
+
/** `${P}-decisions` — the workflow-decision queue (job `decision`). */
|
|
33
|
+
export declare function decisionsName(effPrefix: string): string;
|
|
34
|
+
/** `${P}-step-events` — the streamed local-step-lifecycle queue (job `stepEvent`). */
|
|
35
|
+
export declare function stepEventsName(effPrefix: string): string;
|
|
36
|
+
/** `${P}-heartbeat` — the run / long-step liveness pub/sub channel. */
|
|
37
|
+
export declare function heartbeatChannel(effPrefix: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* `${P}-control` — the control-plane broadcast channel. Provided ONLY so tests can assert the name;
|
|
40
|
+
* the transport does NOT publish/subscribe it (the shipped `RedisControlPlane` owns the control
|
|
41
|
+
* plane). Kept here so the one place that knows the naming contract stays authoritative.
|
|
42
|
+
*/
|
|
43
|
+
export declare function controlChannel(effPrefix: string): string;
|
|
44
|
+
/** `${P}-start-run` — the queue a store-less tenant enqueues start-run requests on (job `startRun`). */
|
|
45
|
+
export declare function startRunName(effPrefix: string): string;
|
|
46
|
+
/** `${P}-run-request` — the queue a store-less tenant enqueues read/control requests on (job `runRequest`). */
|
|
47
|
+
export declare function runRequestName(effPrefix: string): string;
|
|
48
|
+
/** `${P}-run-reply` — the shared pub/sub channel the control plane publishes {@link RunReply}s on;
|
|
49
|
+
* every tenant subscribes and filters by `requestId` client-side. */
|
|
50
|
+
export declare function runReplyChannel(effPrefix: string): string;
|
|
51
|
+
/** `${P}-tenant-events-${tenant}` — the per-tenant pub/sub channel the control plane re-publishes a
|
|
52
|
+
* tenant's lifecycle events on, so a store-less tenant live-tails only ITS OWN runs. */
|
|
53
|
+
export declare function tenantEventsChannel(effPrefix: string, tenant: string): string;
|
|
54
|
+
/** Common prefix of every worker-liveness key (used to SCAN for live routing tokens). */
|
|
55
|
+
export declare function workerHeartbeatKeyPrefix(effPrefix: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* `${P}-worker-heartbeat:${token}:${instanceId}` — one TTL'd liveness key per (routing token,
|
|
58
|
+
* instance). Its ABSENCE (expiry) is the "worker gone/stalled" signal a monitor watches. Neither the
|
|
59
|
+
* token nor the instanceId carries a `:` here, so the token is the segment between the fixed prefix
|
|
60
|
+
* and the next `:` — the parse `listWorkerGroups` relies on.
|
|
61
|
+
*/
|
|
62
|
+
export declare function workerHeartbeatKey(effPrefix: string, token: string, instanceId: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Prefix of every full-descriptor key on a routing `token`: `${P}-worker-descriptor:${token}:` —
|
|
65
|
+
* used to SCAN the live {@link import('../../handshake/descriptor.js').WorkerDescriptor}s a worker
|
|
66
|
+
* runtime publishes per token (design §7.2). BYTE-IDENTICAL to the worker-runtime's `workerDescriptorKey`
|
|
67
|
+
* layout (`${P}-worker-descriptor:<token>:<instance>`), computed here too so the transport reads the
|
|
68
|
+
* descriptor keyspace without reaching into the worker subpath.
|
|
69
|
+
*/
|
|
70
|
+
export declare function workerDescriptorTokenPrefix(effPrefix: string, token: string): string;
|
|
71
|
+
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../../../src/transports/bullmq/naming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAExE;;;;;;;;GAQG;AAEH,mGAAmG;AACnG,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAErF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEhF;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wGAAwG;AACxG,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,+GAA+G;AAC/G,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;sEACsE;AACtE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;yFACyF;AACzF,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,yFAAyF;AACzF,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/F;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { sanitizeQueueToken, tenantGroup } from '../../tenant-group.js';
|
|
2
|
+
/**
|
|
3
|
+
* Broker naming for the aviary-compatible BullMQ transport — the byte-for-byte queue / channel / key
|
|
4
|
+
* names a Python aviary worker (or a NestJS `BullMQTransport`) also computes, so a mixed-language
|
|
5
|
+
* fleet lands on the SAME Redis keys. Every name is derived here and NOWHERE else, so a single place
|
|
6
|
+
* owns the cross-SDK contract (see docs/superpowers/specs/2026-07-17-store-less-cluster-design.md §6.1).
|
|
7
|
+
*
|
|
8
|
+
* These are pure string builders (no Redis, no bullmq) so they unit-test in isolation and the wire
|
|
9
|
+
* naming can be proven byte-identical to the golden fixtures without a broker.
|
|
10
|
+
*/
|
|
11
|
+
/** Re-exported so a caller computing a routing token uses the exact same sanitize/suffix rules. */
|
|
12
|
+
export { sanitizeQueueToken, tenantGroup };
|
|
13
|
+
/**
|
|
14
|
+
* The prefix every name is built from, folding in the deployment namespace per the cross-SDK rule: a
|
|
15
|
+
* set, non-`"default"` namespace appends `-<namespace>`; an unset or `"default"` namespace yields the
|
|
16
|
+
* bare prefix (so the un-namespaced and `"default"` schemes are BYTE-IDENTICAL — production names
|
|
17
|
+
* never change). Keep ALL name builders routed through this; a single direct `prefix` concat would
|
|
18
|
+
* land a worker on a different queue than the engine and silently split the fleet.
|
|
19
|
+
*/
|
|
20
|
+
export function effectivePrefix(prefix, namespace) {
|
|
21
|
+
return namespace && namespace !== 'default' ? `${prefix}-${namespace}` : prefix;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The final routing token a step/workflow `name` dispatches to / a worker subscribes on:
|
|
25
|
+
* `tenantGroup(sanitizeQueueToken(name), partition)`. `:`→`-` (BullMQ forbids `:` in a queue name),
|
|
26
|
+
* `.` kept, and a non-empty/non-`default` partition suffixes `@<partition>`. Apply IDENTICALLY at
|
|
27
|
+
* dispatch and subscribe or a step routes to one token and is served from another (silently never run).
|
|
28
|
+
*/
|
|
29
|
+
export function routingToken(name, partition) {
|
|
30
|
+
return tenantGroup(sanitizeQueueToken(name), partition);
|
|
31
|
+
}
|
|
32
|
+
/** `${P}-tasks-${token}` — the per-routing-token task queue (jobs `task` / `workflow`). */
|
|
33
|
+
export function tasksName(effPrefix, token) {
|
|
34
|
+
return `${effPrefix}-tasks-${token}`;
|
|
35
|
+
}
|
|
36
|
+
/** `${P}-results` — the shared step-result queue (job `result`). */
|
|
37
|
+
export function resultsName(effPrefix) {
|
|
38
|
+
return `${effPrefix}-results`;
|
|
39
|
+
}
|
|
40
|
+
/** `${P}-decisions` — the workflow-decision queue (job `decision`). */
|
|
41
|
+
export function decisionsName(effPrefix) {
|
|
42
|
+
return `${effPrefix}-decisions`;
|
|
43
|
+
}
|
|
44
|
+
/** `${P}-step-events` — the streamed local-step-lifecycle queue (job `stepEvent`). */
|
|
45
|
+
export function stepEventsName(effPrefix) {
|
|
46
|
+
return `${effPrefix}-step-events`;
|
|
47
|
+
}
|
|
48
|
+
/** `${P}-heartbeat` — the run / long-step liveness pub/sub channel. */
|
|
49
|
+
export function heartbeatChannel(effPrefix) {
|
|
50
|
+
return `${effPrefix}-heartbeat`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `${P}-control` — the control-plane broadcast channel. Provided ONLY so tests can assert the name;
|
|
54
|
+
* the transport does NOT publish/subscribe it (the shipped `RedisControlPlane` owns the control
|
|
55
|
+
* plane). Kept here so the one place that knows the naming contract stays authoritative.
|
|
56
|
+
*/
|
|
57
|
+
export function controlChannel(effPrefix) {
|
|
58
|
+
return `${effPrefix}-control`;
|
|
59
|
+
}
|
|
60
|
+
/** `${P}-start-run` — the queue a store-less tenant enqueues start-run requests on (job `startRun`). */
|
|
61
|
+
export function startRunName(effPrefix) {
|
|
62
|
+
return `${effPrefix}-start-run`;
|
|
63
|
+
}
|
|
64
|
+
/** `${P}-run-request` — the queue a store-less tenant enqueues read/control requests on (job `runRequest`). */
|
|
65
|
+
export function runRequestName(effPrefix) {
|
|
66
|
+
return `${effPrefix}-run-request`;
|
|
67
|
+
}
|
|
68
|
+
/** `${P}-run-reply` — the shared pub/sub channel the control plane publishes {@link RunReply}s on;
|
|
69
|
+
* every tenant subscribes and filters by `requestId` client-side. */
|
|
70
|
+
export function runReplyChannel(effPrefix) {
|
|
71
|
+
return `${effPrefix}-run-reply`;
|
|
72
|
+
}
|
|
73
|
+
/** `${P}-tenant-events-${tenant}` — the per-tenant pub/sub channel the control plane re-publishes a
|
|
74
|
+
* tenant's lifecycle events on, so a store-less tenant live-tails only ITS OWN runs. */
|
|
75
|
+
export function tenantEventsChannel(effPrefix, tenant) {
|
|
76
|
+
return `${effPrefix}-tenant-events-${tenant}`;
|
|
77
|
+
}
|
|
78
|
+
/** Common prefix of every worker-liveness key (used to SCAN for live routing tokens). */
|
|
79
|
+
export function workerHeartbeatKeyPrefix(effPrefix) {
|
|
80
|
+
return `${effPrefix}-worker-heartbeat:`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* `${P}-worker-heartbeat:${token}:${instanceId}` — one TTL'd liveness key per (routing token,
|
|
84
|
+
* instance). Its ABSENCE (expiry) is the "worker gone/stalled" signal a monitor watches. Neither the
|
|
85
|
+
* token nor the instanceId carries a `:` here, so the token is the segment between the fixed prefix
|
|
86
|
+
* and the next `:` — the parse `listWorkerGroups` relies on.
|
|
87
|
+
*/
|
|
88
|
+
export function workerHeartbeatKey(effPrefix, token, instanceId) {
|
|
89
|
+
return `${workerHeartbeatKeyPrefix(effPrefix)}${token}:${instanceId}`;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Prefix of every full-descriptor key on a routing `token`: `${P}-worker-descriptor:${token}:` —
|
|
93
|
+
* used to SCAN the live {@link import('../../handshake/descriptor.js').WorkerDescriptor}s a worker
|
|
94
|
+
* runtime publishes per token (design §7.2). BYTE-IDENTICAL to the worker-runtime's `workerDescriptorKey`
|
|
95
|
+
* layout (`${P}-worker-descriptor:<token>:<instance>`), computed here too so the transport reads the
|
|
96
|
+
* descriptor keyspace without reaching into the worker subpath.
|
|
97
|
+
*/
|
|
98
|
+
export function workerDescriptorTokenPrefix(effPrefix, token) {
|
|
99
|
+
return `${effPrefix}-worker-descriptor:${token}:`;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../../../../src/transports/bullmq/naming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAExE;;;;;;;;GAQG;AAEH,mGAAmG;AACnG,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,SAA6B;IAC3E,OAAO,SAAS,IAAI,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AAClF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAA6B;IACtE,OAAO,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;AAC1D,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,KAAa;IACxD,OAAO,GAAG,SAAS,UAAU,KAAK,EAAE,CAAC;AACvC,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,GAAG,SAAS,UAAU,CAAC;AAChC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,OAAO,GAAG,SAAS,YAAY,CAAC;AAClC,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,GAAG,SAAS,cAAc,CAAC;AACpC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,GAAG,SAAS,YAAY,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,GAAG,SAAS,UAAU,CAAC;AAChC,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,GAAG,SAAS,YAAY,CAAC;AAClC,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,GAAG,SAAS,cAAc,CAAC;AACpC,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,OAAO,GAAG,SAAS,YAAY,CAAC;AAClC,CAAC;AAED;yFACyF;AACzF,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,MAAc;IACnE,OAAO,GAAG,SAAS,kBAAkB,MAAM,EAAE,CAAC;AAChD,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,wBAAwB,CAAC,SAAiB;IACxD,OAAO,GAAG,SAAS,oBAAoB,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,KAAa,EAAE,UAAkB;IACrF,OAAO,GAAG,wBAAwB,CAAC,SAAS,CAAC,GAAG,KAAK,IAAI,UAAU,EAAE,CAAC;AACxE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,SAAiB,EAAE,KAAa;IAC1E,OAAO,GAAG,SAAS,sBAAsB,KAAK,GAAG,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map the engine's per-call `priority` (higher = more urgent, default/absent = unprioritised) onto a
|
|
3
|
+
* BullMQ job `priority` (lower = more urgent). Returns `undefined` for an absent priority so the
|
|
4
|
+
* default FIFO path is untouched. `clamp(round(1_048_576 - priority), 1, 2_097_151)` — byte-identical
|
|
5
|
+
* to the aviary transport (spec §6.3).
|
|
6
|
+
*/
|
|
7
|
+
export declare function toBrokerPriority(priority?: number): number | undefined;
|
|
8
|
+
/** Worker-liveness heartbeat cadence: refresh every 10s, key TTL 35s (comfortably > interval so one
|
|
9
|
+
* slow refresh doesn't flap). Matches the aviary/Python `_HEARTBEAT_*` constants. */
|
|
10
|
+
export declare const WORKER_HEARTBEAT_INTERVAL_MS = 10000;
|
|
11
|
+
export declare const WORKER_HEARTBEAT_TTL_SECONDS = 35;
|
|
12
|
+
/** How long a FAILED task job's payload is retained before BullMQ GCs it — long enough for a peer's
|
|
13
|
+
* stalled-check + the terminal-failure bridge to read its `RemoteTask`, bounded so failures don't
|
|
14
|
+
* accumulate. 24h, matching aviary's `TASK_FAILED_RETENTION_SECONDS`. */
|
|
15
|
+
export declare const TASK_FAILED_RETENTION_SECONDS: number;
|
|
16
|
+
/**
|
|
17
|
+
* Stable per-process id stamped on the worker-heartbeat keys: `ts-<host>-<pid>` (the Python SDK uses
|
|
18
|
+
* `py-<host>-<pid>`), so N replicas of a group each show as a distinct worker and a reader can tell
|
|
19
|
+
* which runtime a worker is. Args are injectable for a deterministic test.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildInstanceId(host?: string, pid?: number): string;
|
|
22
|
+
/** BullMQ `add` options for a NON-task job (result/decision/stepEvent): `removeOnComplete`/
|
|
23
|
+
* `removeOnFail` both `true` (spec §6.3), plus a translated `priority` only when set. */
|
|
24
|
+
export interface JobOptions {
|
|
25
|
+
removeOnComplete: true;
|
|
26
|
+
removeOnFail: true;
|
|
27
|
+
priority?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function jobOptions(priority?: number): JobOptions;
|
|
30
|
+
/** BullMQ `add` options for a TASK job (step/workflow dispatch): like {@link jobOptions} but
|
|
31
|
+
* `removeOnFail` is age-bounded retention (`{ age: 86400 }`) so a crashed worker's failed job keeps
|
|
32
|
+
* its `RemoteTask` payload long enough for the terminal-failure bridge to rebuild a StepResult. */
|
|
33
|
+
export interface TaskJobOptions {
|
|
34
|
+
removeOnComplete: true;
|
|
35
|
+
removeOnFail: {
|
|
36
|
+
age: number;
|
|
37
|
+
};
|
|
38
|
+
priority?: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function taskJobOptions(priority?: number): TaskJobOptions;
|
|
41
|
+
/**
|
|
42
|
+
* The value written to a worker-liveness key: JSON `{"ts": <epochMs>}`. Epoch MILLISECONDS (readers
|
|
43
|
+
* normalise seconds→ms only as a legacy fallback). Byte-compatible with the Python worker's minimal
|
|
44
|
+
* form and accepted by the aviary reader (which tolerates a missing `status`).
|
|
45
|
+
*/
|
|
46
|
+
export declare function heartbeatKeyValue(nowMs?: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* Parse a worker-heartbeat key value into `{ lastBeatAt }`, accepting BOTH the `{"ts":…}` JSON (this
|
|
49
|
+
* SDK / newer SDKs) and an older bare timestamp string (the Python SDK's seconds / a legacy ms value).
|
|
50
|
+
* A bare number or a `ts` below {@link EPOCH_MS_THRESHOLD} is treated as seconds and scaled to ms.
|
|
51
|
+
* Robust to a missing/garbled value (→ `lastBeatAt: 0`).
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseHeartbeatValue(raw: string | null): {
|
|
54
|
+
lastBeatAt: number;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=serialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../../../src/transports/bullmq/serialization.ts"],"names":[],"mappings":"AAuBA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAItE;AAED;sFACsF;AACtF,eAAO,MAAM,4BAA4B,QAAS,CAAC;AACnD,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;0EAE0E;AAC1E,eAAO,MAAM,6BAA6B,QAAe,CAAC;AAM1D;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAmB,EAAE,GAAG,GAAE,MAAoB,GAAG,MAAM,CAE5F;AAED;0FAC0F;AAC1F,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,IAAI,CAAC;IACvB,YAAY,EAAE,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAOxD;AAED;;oGAEoG;AACpG,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,IAAI,CAAC;IACvB,YAAY,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,CAOhE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,GAAE,MAAmB,GAAG,MAAM,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAkB9E"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { hostname } from 'node:os';
|
|
2
|
+
/**
|
|
3
|
+
* Serialization for the aviary-compatible BullMQ transport — the byte-for-byte job options, priority
|
|
4
|
+
* mapping, instance id and worker-heartbeat value a Python aviary worker (or a NestJS
|
|
5
|
+
* `BullMQTransport`) also produce/consume. Pure (no bullmq, no Redis) so the wire contract is proven
|
|
6
|
+
* against the golden fixtures without a broker.
|
|
7
|
+
*
|
|
8
|
+
* The wire DTOs themselves (`RemoteTask`/`StepResult`/`Heartbeat`/`WorkflowTask`/…) cross the queue
|
|
9
|
+
* as PLAIN JSON with NO envelope — the DTO **is** the BullMQ job's `data` (BullMQ `JSON.stringify`s it
|
|
10
|
+
* into the job hash). Their dates are already epoch-ms numbers and their optionals are omitted when
|
|
11
|
+
* absent, so a straight `queue.add(jobName, dto, opts)` is byte-identical across SDKs; there is no
|
|
12
|
+
* transform to apply here beyond the job OPTIONS below.
|
|
13
|
+
*/
|
|
14
|
+
// BullMQ priority is the INVERSE of the durable engine's: BullMQ runs the LOWEST number first
|
|
15
|
+
// (1..2_097_151), while the engine's admission `priority` is "higher wins". Translate so one
|
|
16
|
+
// convention ("higher = more urgent") holds end-to-end. `BASELINE - p` keeps relative order (a higher
|
|
17
|
+
// `p` yields a lower — more urgent — BullMQ number), clamped into BullMQ's valid range, centred on the
|
|
18
|
+
// range midpoint so callers have headroom both above and below the default.
|
|
19
|
+
const BROKER_PRIORITY_MAX = 2_097_151;
|
|
20
|
+
const BROKER_PRIORITY_BASELINE = 1_048_576;
|
|
21
|
+
/**
|
|
22
|
+
* Map the engine's per-call `priority` (higher = more urgent, default/absent = unprioritised) onto a
|
|
23
|
+
* BullMQ job `priority` (lower = more urgent). Returns `undefined` for an absent priority so the
|
|
24
|
+
* default FIFO path is untouched. `clamp(round(1_048_576 - priority), 1, 2_097_151)` — byte-identical
|
|
25
|
+
* to the aviary transport (spec §6.3).
|
|
26
|
+
*/
|
|
27
|
+
export function toBrokerPriority(priority) {
|
|
28
|
+
if (priority == null)
|
|
29
|
+
return undefined;
|
|
30
|
+
const mapped = Math.round(BROKER_PRIORITY_BASELINE - priority);
|
|
31
|
+
return Math.min(BROKER_PRIORITY_MAX, Math.max(1, mapped));
|
|
32
|
+
}
|
|
33
|
+
/** Worker-liveness heartbeat cadence: refresh every 10s, key TTL 35s (comfortably > interval so one
|
|
34
|
+
* slow refresh doesn't flap). Matches the aviary/Python `_HEARTBEAT_*` constants. */
|
|
35
|
+
export const WORKER_HEARTBEAT_INTERVAL_MS = 10_000;
|
|
36
|
+
export const WORKER_HEARTBEAT_TTL_SECONDS = 35;
|
|
37
|
+
/** How long a FAILED task job's payload is retained before BullMQ GCs it — long enough for a peer's
|
|
38
|
+
* stalled-check + the terminal-failure bridge to read its `RemoteTask`, bounded so failures don't
|
|
39
|
+
* accumulate. 24h, matching aviary's `TASK_FAILED_RETENTION_SECONDS`. */
|
|
40
|
+
export const TASK_FAILED_RETENTION_SECONDS = 24 * 60 * 60;
|
|
41
|
+
// Epoch values below this are seconds (Python's `time.time()`), at/above are milliseconds (the TS
|
|
42
|
+
// SDKs). Normalise to ms. ~1e12 ms ≈ year 2001; ~1e12 s is year 33658 — unambiguous.
|
|
43
|
+
const EPOCH_MS_THRESHOLD = 1e12;
|
|
44
|
+
/**
|
|
45
|
+
* Stable per-process id stamped on the worker-heartbeat keys: `ts-<host>-<pid>` (the Python SDK uses
|
|
46
|
+
* `py-<host>-<pid>`), so N replicas of a group each show as a distinct worker and a reader can tell
|
|
47
|
+
* which runtime a worker is. Args are injectable for a deterministic test.
|
|
48
|
+
*/
|
|
49
|
+
export function buildInstanceId(host = hostname(), pid = process.pid) {
|
|
50
|
+
return `ts-${host}-${pid}`;
|
|
51
|
+
}
|
|
52
|
+
export function jobOptions(priority) {
|
|
53
|
+
const brokerPriority = toBrokerPriority(priority);
|
|
54
|
+
return {
|
|
55
|
+
removeOnComplete: true,
|
|
56
|
+
removeOnFail: true,
|
|
57
|
+
...(brokerPriority != null ? { priority: brokerPriority } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function taskJobOptions(priority) {
|
|
61
|
+
const brokerPriority = toBrokerPriority(priority);
|
|
62
|
+
return {
|
|
63
|
+
removeOnComplete: true,
|
|
64
|
+
removeOnFail: { age: TASK_FAILED_RETENTION_SECONDS },
|
|
65
|
+
...(brokerPriority != null ? { priority: brokerPriority } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The value written to a worker-liveness key: JSON `{"ts": <epochMs>}`. Epoch MILLISECONDS (readers
|
|
70
|
+
* normalise seconds→ms only as a legacy fallback). Byte-compatible with the Python worker's minimal
|
|
71
|
+
* form and accepted by the aviary reader (which tolerates a missing `status`).
|
|
72
|
+
*/
|
|
73
|
+
export function heartbeatKeyValue(nowMs = Date.now()) {
|
|
74
|
+
return JSON.stringify({ ts: nowMs });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Parse a worker-heartbeat key value into `{ lastBeatAt }`, accepting BOTH the `{"ts":…}` JSON (this
|
|
78
|
+
* SDK / newer SDKs) and an older bare timestamp string (the Python SDK's seconds / a legacy ms value).
|
|
79
|
+
* A bare number or a `ts` below {@link EPOCH_MS_THRESHOLD} is treated as seconds and scaled to ms.
|
|
80
|
+
* Robust to a missing/garbled value (→ `lastBeatAt: 0`).
|
|
81
|
+
*/
|
|
82
|
+
export function parseHeartbeatValue(raw) {
|
|
83
|
+
if (raw == null)
|
|
84
|
+
return { lastBeatAt: 0 };
|
|
85
|
+
const trimmed = raw.trim();
|
|
86
|
+
if (trimmed === '')
|
|
87
|
+
return { lastBeatAt: 0 };
|
|
88
|
+
const toMs = (n) => Number.isFinite(n) ? (n < EPOCH_MS_THRESHOLD ? n * 1000 : n) : 0;
|
|
89
|
+
// Old bare-number form (no JSON braces): a plain ms/seconds timestamp.
|
|
90
|
+
if (!trimmed.startsWith('{'))
|
|
91
|
+
return { lastBeatAt: toMs(Number(trimmed)) };
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(trimmed);
|
|
94
|
+
return { lastBeatAt: typeof parsed.ts === 'number' ? toMs(parsed.ts) : 0 };
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Malformed JSON — fall back to a numeric read so a partially-written value still yields a beat.
|
|
98
|
+
return { lastBeatAt: toMs(Number(trimmed)) };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../../../src/transports/bullmq/serialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,6 +61,29 @@ export interface QueueTransportConfig {
|
|
|
61
61
|
/** Stable id for this process (stamped on heartbeats / control `from`). Default a random id. */
|
|
62
62
|
instanceId?: string;
|
|
63
63
|
}
|
|
64
|
+
/** Options for the aviary-compatible BullMQ transport (the cross-ecosystem interop path). */
|
|
65
|
+
export interface BullMQTransportConfig {
|
|
66
|
+
/**
|
|
67
|
+
* ioredis connection — `ConnectionOptions` (host/port/…) or a `Redis` instance — handed straight to
|
|
68
|
+
* BullMQ and ioredis. Required: this transport talks to a real Redis (that is the whole point of the
|
|
69
|
+
* cross-language path). Typed loosely (`unknown`) so the `bullmq`/`ioredis` types are not pulled into
|
|
70
|
+
* the config surface of a fleet that never selects this transport.
|
|
71
|
+
*/
|
|
72
|
+
connection: unknown;
|
|
73
|
+
/**
|
|
74
|
+
* Logical isolation partition suffixing every per-handler tasks queue this instance subscribes to.
|
|
75
|
+
* Unset routes each handler to the bare (sanitized) handler name.
|
|
76
|
+
*/
|
|
77
|
+
partition?: string;
|
|
78
|
+
/** Key prefix namespacing the durable queues. Default `durable`. */
|
|
79
|
+
prefix?: string;
|
|
80
|
+
/** Logical deployment namespace, segmenting every queue/channel/key. `"default"`/absent = unchanged. */
|
|
81
|
+
namespace?: string;
|
|
82
|
+
/** How many tasks a worker runs concurrently from each of its queues (BullMQ `Worker` concurrency). Default 1. */
|
|
83
|
+
concurrency?: number;
|
|
84
|
+
/** Stable id for this process (stamped on the worker-liveness keys). Default `ts-<host>-<pid>`. */
|
|
85
|
+
instanceId?: string;
|
|
86
|
+
}
|
|
64
87
|
/** Options for the DB-table-backed (`@adonisjs/lucid`) transport. */
|
|
65
88
|
export interface DbTransportConfig {
|
|
66
89
|
/** Worker group this instance serves (required on a worker process to register handlers). */
|
|
@@ -94,6 +117,14 @@ export declare const transports: {
|
|
|
94
117
|
eventEmitter(config?: EventEmitterTransportConfig): TransportFactory;
|
|
95
118
|
/** Run remote steps cross-process over `@adonisjs/queue`, using a connection from `config/queue.ts`. */
|
|
96
119
|
queue(config?: QueueTransportConfig): TransportFactory;
|
|
120
|
+
/**
|
|
121
|
+
* Run remote steps + workflow tasks cross-process AND cross-ecosystem over the real `bullmq` npm
|
|
122
|
+
* package, byte-compatible with the aviary (`nestjs-durable`) BullMQ transport and its Python
|
|
123
|
+
* raw-redis worker — so an Adonis engine and a Python/NestJS worker interoperate on one Redis. Pair
|
|
124
|
+
* it with `controlPlanes.redis(...)` for the `${prefix}-control` broadcast (this transport does not
|
|
125
|
+
* reimplement the control plane). `bullmq`/`ioredis` are imported lazily, only when selected.
|
|
126
|
+
*/
|
|
127
|
+
bullmq(config: BullMQTransportConfig): TransportFactory;
|
|
97
128
|
/** Run remote steps cross-process over the app's database, using `@adonisjs/lucid` — no broker. */
|
|
98
129
|
db(config?: DbTransportConfig): TransportFactory;
|
|
99
130
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/transports/factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIhE;;;;;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,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;CAErC;AAED,yFAAyF;AACzF,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+GAA+G;IAC/G,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;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;;;;OAIG;qBACa,qBAAqB,GAAQ,gBAAgB;IAI7D;;;;;OAKG;0BACkB,2BAA2B,GAAQ,gBAAgB;IAUxE,wGAAwG;mBAC1F,oBAAoB,GAAQ,gBAAgB;IAc1D,mGAAmG;gBACxF,iBAAiB,GAAQ,gBAAgB;CAgBrD,CAAC"}
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/transports/factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIhE;;;;;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,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;CAErC;AAED,yFAAyF;AACzF,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+GAA+G;IAC/G,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;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,6FAA6F;AAC7F,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wGAAwG;IACxG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kHAAkH;IAClH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mGAAmG;IACnG,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;;;;OAIG;qBACa,qBAAqB,GAAQ,gBAAgB;IAI7D;;;;;OAKG;0BACkB,2BAA2B,GAAQ,gBAAgB;IAUxE,wGAAwG;mBAC1F,oBAAoB,GAAQ,gBAAgB;IAc1D;;;;;;OAMG;mBACY,qBAAqB,GAAG,gBAAgB;IAevD,mGAAmG;gBACxF,iBAAiB,GAAQ,gBAAgB;CAgBrD,CAAC"}
|
|
@@ -56,6 +56,27 @@ export const transports = {
|
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
58
|
},
|
|
59
|
+
/**
|
|
60
|
+
* Run remote steps + workflow tasks cross-process AND cross-ecosystem over the real `bullmq` npm
|
|
61
|
+
* package, byte-compatible with the aviary (`nestjs-durable`) BullMQ transport and its Python
|
|
62
|
+
* raw-redis worker — so an Adonis engine and a Python/NestJS worker interoperate on one Redis. Pair
|
|
63
|
+
* it with `controlPlanes.redis(...)` for the `${prefix}-control` broadcast (this transport does not
|
|
64
|
+
* reimplement the control plane). `bullmq`/`ioredis` are imported lazily, only when selected.
|
|
65
|
+
*/
|
|
66
|
+
bullmq(config) {
|
|
67
|
+
return async () => {
|
|
68
|
+
const { BullMQTransport } = await import('./bullmq/bullmq-transport.js');
|
|
69
|
+
const { createBullMQDeps } = await import('./bullmq/deps.js');
|
|
70
|
+
const deps = await createBullMQDeps(config.connection, config.concurrency ?? 1);
|
|
71
|
+
return new BullMQTransport({
|
|
72
|
+
deps,
|
|
73
|
+
...(config.partition !== undefined ? { partition: config.partition } : {}),
|
|
74
|
+
...(config.prefix !== undefined ? { prefix: config.prefix } : {}),
|
|
75
|
+
...(config.namespace !== undefined ? { namespace: config.namespace } : {}),
|
|
76
|
+
...(config.instanceId !== undefined ? { instanceId: config.instanceId } : {}),
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
},
|
|
59
80
|
/** Run remote steps cross-process over the app's database, using `@adonisjs/lucid` — no broker. */
|
|
60
81
|
db(config = {}) {
|
|
61
82
|
return async (ctx) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/transports/factory.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/transports/factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@adonis-agora/durable/worker` — the LEAN, store-less worker entry (design §4 packaging).
|
|
3
|
+
*
|
|
4
|
+
* This module and its whole transitive graph import NO Lucid (and no store at all), so a thin worker
|
|
5
|
+
* pod's dependency graph stays lean without a separate package. That store-less-ness is a STRUCTURAL
|
|
6
|
+
* fact enforced by the `no-lucid` test (test/worker-runtime/no-lucid.spec.ts), not a convention: it
|
|
7
|
+
* walks this module's transitive `import` graph and fails if `@adonisjs/lucid` (or any store module)
|
|
8
|
+
* ever appears. Keep it that way — only add imports that are themselves Lucid-free.
|
|
9
|
+
*
|
|
10
|
+
* A thin worker: build a transport (e.g. the wave-1 `BullMQTransport`), construct a {@link WorkerRuntime}
|
|
11
|
+
* over it, register `app/steps` (and advertise `app/workflows` names) via the re-exported
|
|
12
|
+
* `step-discovery` helpers, then `runtime.start()`. The `node ace durable:worker` command wires exactly
|
|
13
|
+
* this from `config/durable.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export { WorkerRuntime, WORKER_SDK, type WorkerRuntimeOptions, type WorkerTransport, type WorkerRuntimeLogger, } from './worker-runtime.js';
|
|
16
|
+
export { NoopWorkerRegistry, RedisWorkerRegistry, type WorkerRegistry, type DescriptorRedis, } from './registry.js';
|
|
17
|
+
export { workerDescriptorKey, workerDescriptorKeyPrefix, workerHeartbeatKey, effectivePrefix, routingToken, } from './naming.js';
|
|
18
|
+
export { CURRENT_PROTOCOL_VERSION, descriptorHash, heartbeatStatus, normalizeDescriptor, type WorkerDescriptor, type HeartbeatStatus, type WorkerLifecycle, } from '../handshake/descriptor.js';
|
|
19
|
+
export { registerStep, registerSteps, registerStepsFromDir, registerStepsFromBarrel, collectSteps, type StepServer, type DiscoveredStep, type StepsBarrel, } from '../step-discovery.js';
|
|
20
|
+
export { runStepHandler, type StepHandler } from '../protocol.js';
|
|
21
|
+
export { runWorkflowTurn, isWorkflowTask, WorkflowStepFailedError, WorkflowGatherFailedError, WorkflowNondeterminismError, WorkflowTurnCancelled, type WorkflowTurnCtx, type WorkflowBody, type WorkflowBodyResolver, type WorkflowTurnHandler, type RunWorkflowTurnOptions, type GatherMode, type GatherCall, type GatherItemError, } from '../workflow-turn.js';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/worker-runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,aAAa,EACb,UAAU,EACV,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,kBAAkB,EAClB,eAAe,EACf,YAAY,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,uBAAuB,EACvB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlE,OAAO,EACL,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,2BAA2B,EAC3B,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@adonis-agora/durable/worker` — the LEAN, store-less worker entry (design §4 packaging).
|
|
3
|
+
*
|
|
4
|
+
* This module and its whole transitive graph import NO Lucid (and no store at all), so a thin worker
|
|
5
|
+
* pod's dependency graph stays lean without a separate package. That store-less-ness is a STRUCTURAL
|
|
6
|
+
* fact enforced by the `no-lucid` test (test/worker-runtime/no-lucid.spec.ts), not a convention: it
|
|
7
|
+
* walks this module's transitive `import` graph and fails if `@adonisjs/lucid` (or any store module)
|
|
8
|
+
* ever appears. Keep it that way — only add imports that are themselves Lucid-free.
|
|
9
|
+
*
|
|
10
|
+
* A thin worker: build a transport (e.g. the wave-1 `BullMQTransport`), construct a {@link WorkerRuntime}
|
|
11
|
+
* over it, register `app/steps` (and advertise `app/workflows` names) via the re-exported
|
|
12
|
+
* `step-discovery` helpers, then `runtime.start()`. The `node ace durable:worker` command wires exactly
|
|
13
|
+
* this from `config/durable.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export { WorkerRuntime, WORKER_SDK, } from './worker-runtime.js';
|
|
16
|
+
export { NoopWorkerRegistry, RedisWorkerRegistry, } from './registry.js';
|
|
17
|
+
export { workerDescriptorKey, workerDescriptorKeyPrefix, workerHeartbeatKey, effectivePrefix, routingToken, } from './naming.js';
|
|
18
|
+
// The handshake descriptor surface (design §7) — re-exported for worker authors; itself Lucid-free.
|
|
19
|
+
export { CURRENT_PROTOCOL_VERSION, descriptorHash, heartbeatStatus, normalizeDescriptor, } from '../handshake/descriptor.js';
|
|
20
|
+
// Step registration/discovery helpers (the `app/steps` convention) — Lucid-free (fs + pure metadata).
|
|
21
|
+
export { registerStep, registerSteps, registerStepsFromDir, registerStepsFromBarrel, collectSteps, } from '../step-discovery.js';
|
|
22
|
+
// The shared pure worker body + step-handler type (the transport funnels tasks through it).
|
|
23
|
+
export { runStepHandler } from '../protocol.js';
|
|
24
|
+
// The shared pure WORKFLOW-TURN body (replay history → decision) + its authoring surface — what lets a
|
|
25
|
+
// store-less worker execute workflow turns (design §4). Itself Lucid-free (imports only interface types).
|
|
26
|
+
export { runWorkflowTurn, isWorkflowTask, WorkflowStepFailedError, WorkflowGatherFailedError, WorkflowNondeterminismError, WorkflowTurnCancelled, } from '../workflow-turn.js';
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/worker-runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,aAAa,EACb,UAAU,GAIX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,GAGpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,kBAAkB,EAClB,eAAe,EACf,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,oGAAoG;AACpG,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,mBAAmB,GAIpB,MAAM,4BAA4B,CAAC;AAEpC,sGAAsG;AACtG,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,uBAAuB,EACvB,YAAY,GAIb,MAAM,sBAAsB,CAAC;AAE9B,4FAA4F;AAC5F,OAAO,EAAE,cAAc,EAAoB,MAAM,gBAAgB,CAAC;AAElE,uGAAuG;AACvG,0GAA0G;AAC1G,OAAO,EACL,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,2BAA2B,EAC3B,qBAAqB,GAStB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { effectivePrefix, routingToken, workerHeartbeatKey } from '../transports/bullmq/naming.js';
|
|
2
|
+
/**
|
|
3
|
+
* Broker key naming for the store-less {@link import('./worker-runtime.js').WorkerRuntime}'s two-tier
|
|
4
|
+
* advertisement (design §6.2 / §7.2). Built ON TOP of the wave-1 aviary-compatible
|
|
5
|
+
* `transports/bullmq/naming` so the worker-liveness + descriptor keys stay byte-identical across the
|
|
6
|
+
* fleet (a Python worker / NestJS control-plane computes the same names). Pure string builders — no
|
|
7
|
+
* Redis, no bullmq, no Lucid — so the worker subpath stays lean and the names unit-test in isolation.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported here (rather than re-derived) so a caller in the worker subpath never has to reach into
|
|
10
|
+
* the bullmq transport package for the shared sanitize/prefix/token rules.
|
|
11
|
+
*/
|
|
12
|
+
export { effectivePrefix, routingToken, workerHeartbeatKey };
|
|
13
|
+
/**
|
|
14
|
+
* `${P}-worker-descriptor:${token}:${instanceId}` — the full {@link WorkerDescriptor} key (design
|
|
15
|
+
* §6.2). One key per (routing token, instance): the worker publishes its whole descriptor under EACH
|
|
16
|
+
* routing token it serves, mirroring the per-token `${P}-worker-heartbeat:` liveness key so a
|
|
17
|
+
* control-plane scanning a token's keyspace finds both the compact heartbeat (with the ETag) and, when
|
|
18
|
+
* the ETag changed, the rich descriptor to re-read. Neither `token` nor `instanceId` carries a `:`, so
|
|
19
|
+
* the segments parse unambiguously — identical to {@link workerHeartbeatKey}'s layout.
|
|
20
|
+
*/
|
|
21
|
+
export declare function workerDescriptorKey(effPrefix: string, token: string, instanceId: string): string;
|
|
22
|
+
/** Common prefix of every worker-descriptor key (for a control-plane SCAN over live descriptors). */
|
|
23
|
+
export declare function workerDescriptorKeyPrefix(effPrefix: string): string;
|
|
24
|
+
//# sourceMappingURL=naming.d.ts.map
|