@dudousxd/nestjs-durable-core 0.42.0 → 0.43.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/dist/index.cjs +99 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +99 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1636,6 +1636,29 @@ declare class WorkflowEngine {
|
|
|
1636
1636
|
executionTimeout?: string | number;
|
|
1637
1637
|
validateInput?: (input: unknown) => void | Promise<void>;
|
|
1638
1638
|
}): void;
|
|
1639
|
+
/**
|
|
1640
|
+
* The convenience form of {@link registerRemote}: register a workflow whose body runs on a worker
|
|
1641
|
+
* `group` (e.g. the Python `durable-worker`, or a separate TS worker), without hand-building a
|
|
1642
|
+
* {@link RemoteWorkflowExecutor}. It wires the standard broker executor — a `RemoteWorkflowExecutor`
|
|
1643
|
+
* over the engine's own transport, dispatching to `opts.group` — for you, so you write
|
|
1644
|
+
* `engine.remote('processing', { group: 'processing' })` instead of
|
|
1645
|
+
* `engine.registerRemote('processing', '1', { group: 'processing', executor: new RemoteWorkflowExecutor(transport, 'processing') })`.
|
|
1646
|
+
*
|
|
1647
|
+
* Defaults the version to `'1'`. All the other {@link registerRemote} options
|
|
1648
|
+
* (`tags` / `singleton` / `executionTimeout` / `validateInput`) pass straight through. Reach for the
|
|
1649
|
+
* low-level {@link registerRemote} when you need a custom {@link WorkflowExecutor} (a different
|
|
1650
|
+
* transport, a fixed `timeoutMs`, a polyglot stub) — `remote()` is the standard wiring on the rails.
|
|
1651
|
+
*/
|
|
1652
|
+
remote(name: string, opts: {
|
|
1653
|
+
/** Worker group this workflow's turns are dispatched to (also the executor's target group). */
|
|
1654
|
+
group: string;
|
|
1655
|
+
/** Workflow version. Defaults to `'1'`. */
|
|
1656
|
+
version?: string;
|
|
1657
|
+
tags?: string[];
|
|
1658
|
+
singleton?: SingletonConfig;
|
|
1659
|
+
executionTimeout?: string | number;
|
|
1660
|
+
validateInput?: (input: unknown) => void | Promise<void>;
|
|
1661
|
+
}): void;
|
|
1639
1662
|
/**
|
|
1640
1663
|
* Register a flow-control queue referenced by `ctx.call(step, input, { queue })`. Caps concurrent
|
|
1641
1664
|
* in-flight steps and/or the admission rate; blocked calls re-suspend and retry, so the limit is
|
package/dist/index.d.ts
CHANGED
|
@@ -1636,6 +1636,29 @@ declare class WorkflowEngine {
|
|
|
1636
1636
|
executionTimeout?: string | number;
|
|
1637
1637
|
validateInput?: (input: unknown) => void | Promise<void>;
|
|
1638
1638
|
}): void;
|
|
1639
|
+
/**
|
|
1640
|
+
* The convenience form of {@link registerRemote}: register a workflow whose body runs on a worker
|
|
1641
|
+
* `group` (e.g. the Python `durable-worker`, or a separate TS worker), without hand-building a
|
|
1642
|
+
* {@link RemoteWorkflowExecutor}. It wires the standard broker executor — a `RemoteWorkflowExecutor`
|
|
1643
|
+
* over the engine's own transport, dispatching to `opts.group` — for you, so you write
|
|
1644
|
+
* `engine.remote('processing', { group: 'processing' })` instead of
|
|
1645
|
+
* `engine.registerRemote('processing', '1', { group: 'processing', executor: new RemoteWorkflowExecutor(transport, 'processing') })`.
|
|
1646
|
+
*
|
|
1647
|
+
* Defaults the version to `'1'`. All the other {@link registerRemote} options
|
|
1648
|
+
* (`tags` / `singleton` / `executionTimeout` / `validateInput`) pass straight through. Reach for the
|
|
1649
|
+
* low-level {@link registerRemote} when you need a custom {@link WorkflowExecutor} (a different
|
|
1650
|
+
* transport, a fixed `timeoutMs`, a polyglot stub) — `remote()` is the standard wiring on the rails.
|
|
1651
|
+
*/
|
|
1652
|
+
remote(name: string, opts: {
|
|
1653
|
+
/** Worker group this workflow's turns are dispatched to (also the executor's target group). */
|
|
1654
|
+
group: string;
|
|
1655
|
+
/** Workflow version. Defaults to `'1'`. */
|
|
1656
|
+
version?: string;
|
|
1657
|
+
tags?: string[];
|
|
1658
|
+
singleton?: SingletonConfig;
|
|
1659
|
+
executionTimeout?: string | number;
|
|
1660
|
+
validateInput?: (input: unknown) => void | Promise<void>;
|
|
1661
|
+
}): void;
|
|
1639
1662
|
/**
|
|
1640
1663
|
* Register a flow-control queue referenced by `ctx.call(step, input, { queue })`. Caps concurrent
|
|
1641
1664
|
* in-flight steps and/or the admission rate; blocked calls re-suspend and retry, so the limit is
|
package/dist/index.js
CHANGED
|
@@ -700,6 +700,70 @@ function eventMatches(payload, match) {
|
|
|
700
700
|
}
|
|
701
701
|
__name(eventMatches, "eventMatches");
|
|
702
702
|
|
|
703
|
+
// src/remote-workflow-executor.ts
|
|
704
|
+
var taskCounter = 0;
|
|
705
|
+
var RemoteWorkflowExecutor = class {
|
|
706
|
+
static {
|
|
707
|
+
__name(this, "RemoteWorkflowExecutor");
|
|
708
|
+
}
|
|
709
|
+
transport;
|
|
710
|
+
group;
|
|
711
|
+
opts;
|
|
712
|
+
pending = /* @__PURE__ */ new Map();
|
|
713
|
+
subscribed = false;
|
|
714
|
+
constructor(transport, group, opts = {}) {
|
|
715
|
+
this.transport = transport;
|
|
716
|
+
this.group = group;
|
|
717
|
+
this.opts = opts;
|
|
718
|
+
}
|
|
719
|
+
ensureSubscribed() {
|
|
720
|
+
if (this.subscribed) return;
|
|
721
|
+
if (!this.transport.onDecision) {
|
|
722
|
+
throw new Error("transport does not support workflow decisions (onDecision)");
|
|
723
|
+
}
|
|
724
|
+
this.subscribed = true;
|
|
725
|
+
this.transport.onDecision(async (decision) => {
|
|
726
|
+
const resolve = this.pending.get(decision.taskId);
|
|
727
|
+
if (resolve) {
|
|
728
|
+
this.pending.delete(decision.taskId);
|
|
729
|
+
resolve(decision);
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
async advance(run, history) {
|
|
734
|
+
if (!this.transport.dispatchWorkflowTask) {
|
|
735
|
+
throw new Error("transport does not support workflow tasks (dispatchWorkflowTask)");
|
|
736
|
+
}
|
|
737
|
+
this.ensureSubscribed();
|
|
738
|
+
taskCounter += 1;
|
|
739
|
+
const taskId = `${run.id}:wf:${taskCounter}`;
|
|
740
|
+
const task = {
|
|
741
|
+
taskId,
|
|
742
|
+
runId: run.id,
|
|
743
|
+
workflow: run.workflow,
|
|
744
|
+
workflowVersion: run.workflowVersion,
|
|
745
|
+
input: run.input,
|
|
746
|
+
history,
|
|
747
|
+
group: this.group,
|
|
748
|
+
priority: run.priority,
|
|
749
|
+
attempt: 1
|
|
750
|
+
};
|
|
751
|
+
const decision = new Promise((resolve, reject) => {
|
|
752
|
+
this.pending.set(taskId, resolve);
|
|
753
|
+
const { timeoutMs } = this.opts;
|
|
754
|
+
if (timeoutMs) {
|
|
755
|
+
const timer = setTimeout(() => {
|
|
756
|
+
this.pending.delete(taskId);
|
|
757
|
+
reject(new RemoteWorkflowTimeout(taskId, timeoutMs));
|
|
758
|
+
}, timeoutMs);
|
|
759
|
+
timer.unref?.();
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
await this.transport.dispatchWorkflowTask(task);
|
|
763
|
+
return decision;
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
|
|
703
767
|
// src/singleton-gate.ts
|
|
704
768
|
var SINGLETON_RETRY_MS = 1e3;
|
|
705
769
|
var SINGLETON_RETRY_JITTER_MS = 250;
|
|
@@ -801,6 +865,19 @@ var TransportPool = class {
|
|
|
801
865
|
get size() {
|
|
802
866
|
return this.transports.length;
|
|
803
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* The primary (first) transport — the one `dispatch` prefers when no `preferId` is pinned. A
|
|
870
|
+
* {@link RemoteWorkflowExecutor} built by `engine.remote()` rides it (it needs a single
|
|
871
|
+
* `dispatchWorkflowTask`/`onDecision` Transport, not the whole failover pool). Throws if the pool
|
|
872
|
+
* is empty — there is nothing to dispatch a remote workflow over.
|
|
873
|
+
*/
|
|
874
|
+
get primary() {
|
|
875
|
+
const first = this.transports[0];
|
|
876
|
+
if (!first) {
|
|
877
|
+
throw new Error("no transport configured \u2014 engine.remote() needs a transport (or transports)");
|
|
878
|
+
}
|
|
879
|
+
return first.transport;
|
|
880
|
+
}
|
|
804
881
|
/** Register the engine's result/heartbeat/step-event handlers on EVERY transport — a result can come
|
|
805
882
|
* back on whichever one delivered the task, so failover stays symmetric. `onStepEvent` is wired only
|
|
806
883
|
* on transports that carry streamed workflow step lifecycle (BullMQ); others simply skip it. */
|
|
@@ -1720,6 +1797,28 @@ var WorkflowEngine = class {
|
|
|
1720
1797
|
if (!current || isNewerVersion(version, current.version)) this.latest.set(name, registered);
|
|
1721
1798
|
}
|
|
1722
1799
|
/**
|
|
1800
|
+
* The convenience form of {@link registerRemote}: register a workflow whose body runs on a worker
|
|
1801
|
+
* `group` (e.g. the Python `durable-worker`, or a separate TS worker), without hand-building a
|
|
1802
|
+
* {@link RemoteWorkflowExecutor}. It wires the standard broker executor — a `RemoteWorkflowExecutor`
|
|
1803
|
+
* over the engine's own transport, dispatching to `opts.group` — for you, so you write
|
|
1804
|
+
* `engine.remote('processing', { group: 'processing' })` instead of
|
|
1805
|
+
* `engine.registerRemote('processing', '1', { group: 'processing', executor: new RemoteWorkflowExecutor(transport, 'processing') })`.
|
|
1806
|
+
*
|
|
1807
|
+
* Defaults the version to `'1'`. All the other {@link registerRemote} options
|
|
1808
|
+
* (`tags` / `singleton` / `executionTimeout` / `validateInput`) pass straight through. Reach for the
|
|
1809
|
+
* low-level {@link registerRemote} when you need a custom {@link WorkflowExecutor} (a different
|
|
1810
|
+
* transport, a fixed `timeoutMs`, a polyglot stub) — `remote()` is the standard wiring on the rails.
|
|
1811
|
+
*/
|
|
1812
|
+
remote(name, opts) {
|
|
1813
|
+
const { group, version, ...rest } = opts;
|
|
1814
|
+
const executor = new RemoteWorkflowExecutor(this.pool.primary, group);
|
|
1815
|
+
this.registerRemote(name, version ?? "1", {
|
|
1816
|
+
group,
|
|
1817
|
+
executor,
|
|
1818
|
+
...rest
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
/**
|
|
1723
1822
|
* Register a flow-control queue referenced by `ctx.call(step, input, { queue })`. Caps concurrent
|
|
1724
1823
|
* in-flight steps and/or the admission rate; blocked calls re-suspend and retry, so the limit is
|
|
1725
1824
|
* durable. Per engine instance (see {@link QueueConfig}). Registering the same name replaces it.
|
|
@@ -3615,70 +3714,6 @@ function remoteStep(config) {
|
|
|
3615
3714
|
}
|
|
3616
3715
|
__name(remoteStep, "remoteStep");
|
|
3617
3716
|
|
|
3618
|
-
// src/remote-workflow-executor.ts
|
|
3619
|
-
var taskCounter = 0;
|
|
3620
|
-
var RemoteWorkflowExecutor = class {
|
|
3621
|
-
static {
|
|
3622
|
-
__name(this, "RemoteWorkflowExecutor");
|
|
3623
|
-
}
|
|
3624
|
-
transport;
|
|
3625
|
-
group;
|
|
3626
|
-
opts;
|
|
3627
|
-
pending = /* @__PURE__ */ new Map();
|
|
3628
|
-
subscribed = false;
|
|
3629
|
-
constructor(transport, group, opts = {}) {
|
|
3630
|
-
this.transport = transport;
|
|
3631
|
-
this.group = group;
|
|
3632
|
-
this.opts = opts;
|
|
3633
|
-
}
|
|
3634
|
-
ensureSubscribed() {
|
|
3635
|
-
if (this.subscribed) return;
|
|
3636
|
-
if (!this.transport.onDecision) {
|
|
3637
|
-
throw new Error("transport does not support workflow decisions (onDecision)");
|
|
3638
|
-
}
|
|
3639
|
-
this.subscribed = true;
|
|
3640
|
-
this.transport.onDecision(async (decision) => {
|
|
3641
|
-
const resolve = this.pending.get(decision.taskId);
|
|
3642
|
-
if (resolve) {
|
|
3643
|
-
this.pending.delete(decision.taskId);
|
|
3644
|
-
resolve(decision);
|
|
3645
|
-
}
|
|
3646
|
-
});
|
|
3647
|
-
}
|
|
3648
|
-
async advance(run, history) {
|
|
3649
|
-
if (!this.transport.dispatchWorkflowTask) {
|
|
3650
|
-
throw new Error("transport does not support workflow tasks (dispatchWorkflowTask)");
|
|
3651
|
-
}
|
|
3652
|
-
this.ensureSubscribed();
|
|
3653
|
-
taskCounter += 1;
|
|
3654
|
-
const taskId = `${run.id}:wf:${taskCounter}`;
|
|
3655
|
-
const task = {
|
|
3656
|
-
taskId,
|
|
3657
|
-
runId: run.id,
|
|
3658
|
-
workflow: run.workflow,
|
|
3659
|
-
workflowVersion: run.workflowVersion,
|
|
3660
|
-
input: run.input,
|
|
3661
|
-
history,
|
|
3662
|
-
group: this.group,
|
|
3663
|
-
priority: run.priority,
|
|
3664
|
-
attempt: 1
|
|
3665
|
-
};
|
|
3666
|
-
const decision = new Promise((resolve, reject) => {
|
|
3667
|
-
this.pending.set(taskId, resolve);
|
|
3668
|
-
const { timeoutMs } = this.opts;
|
|
3669
|
-
if (timeoutMs) {
|
|
3670
|
-
const timer = setTimeout(() => {
|
|
3671
|
-
this.pending.delete(taskId);
|
|
3672
|
-
reject(new RemoteWorkflowTimeout(taskId, timeoutMs));
|
|
3673
|
-
}, timeoutMs);
|
|
3674
|
-
timer.unref?.();
|
|
3675
|
-
}
|
|
3676
|
-
});
|
|
3677
|
-
await this.transport.dispatchWorkflowTask(task);
|
|
3678
|
-
return decision;
|
|
3679
|
-
}
|
|
3680
|
-
};
|
|
3681
|
-
|
|
3682
3717
|
// src/codec-state-store.ts
|
|
3683
3718
|
var CodecStateStore = class {
|
|
3684
3719
|
static {
|