@dudousxd/nestjs-durable-core 0.44.0 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +5 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -21
- package/dist/index.d.ts +20 -21
- package/dist/index.js +5 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -802,17 +802,17 @@ interface WorkflowExecutor {
|
|
|
802
802
|
*/
|
|
803
803
|
advance?(run: WorkflowRun, history: HistoryEvent[], pendingSignals?: WorkflowTask['pendingSignals']): Promise<WorkflowDecision>;
|
|
804
804
|
/**
|
|
805
|
-
* DISPATCH-AND-SUSPEND (broker-backed, multi-instance safe):
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
805
|
+
* DISPATCH-AND-SUSPEND (broker-backed, multi-instance safe): enqueue the turn to a worker under the
|
|
806
|
+
* ENGINE-SUPPLIED `taskId`, WITHOUT awaiting the decision. The engine generates `taskId`, records it
|
|
807
|
+
* on the run as the awaited marker, AND releases the run's lease — all BEFORE calling this — so the
|
|
808
|
+
* worker's {@link WorkflowDecision} (delivered over {@link Transport.onDecision} and applied DURABLY
|
|
809
|
+
* by {@link WorkflowEngine.completeRemoteDecision}, which looks the run up by `decision.runId`) can
|
|
810
|
+
* never arrive ahead of its marker or contend with a still-held lease and be dropped. This method
|
|
811
|
+
* therefore ONLY enqueues — it owns no taskId generation and returns nothing. No in-memory await, so
|
|
812
|
+
* the decision is never lost to a point-to-point broker handing it to a non-dispatching instance.
|
|
813
|
+
* Provide this OR {@link advance} — exactly one.
|
|
814
|
+
*/
|
|
815
|
+
dispatch?(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
816
816
|
}
|
|
817
817
|
/**
|
|
818
818
|
* A transport in an ordered pool, identified by `id`. The engine dispatches on the first by default
|
|
@@ -2244,15 +2244,16 @@ declare function remoteStep<TInput, TOutput>(config: RemoteStepConfig<TInput, TO
|
|
|
2244
2244
|
|
|
2245
2245
|
/**
|
|
2246
2246
|
* A {@link WorkflowExecutor} backed by a {@link Transport}: it advances a remote workflow by
|
|
2247
|
-
* DISPATCHING a {@link WorkflowTask} over the broker
|
|
2247
|
+
* DISPATCHING a {@link WorkflowTask} over the broker under the ENGINE-SUPPLIED `taskId`, WITHOUT
|
|
2248
2248
|
* awaiting the decision. Pass one to `engine.registerRemote(name, version, { group, executor })` so a
|
|
2249
2249
|
* workflow authored in another SDK (e.g. the Python `durable-worker`) is driven over Redis/BullMQ.
|
|
2250
2250
|
*
|
|
2251
2251
|
* Multi-instance safe by construction: the executor holds NO in-memory state correlating a dispatched
|
|
2252
|
-
* turn to its decision. The engine
|
|
2253
|
-
* worker's {@link import('./interfaces').WorkflowDecision}
|
|
2254
|
-
* `onDecision` and applied DURABLY (by run id) on whatever engine
|
|
2255
|
-
*
|
|
2252
|
+
* turn to its decision. The engine records the `taskId` on the run as the awaited marker AND releases
|
|
2253
|
+
* the run's lease BEFORE calling `dispatch`, so the worker's {@link import('./interfaces').WorkflowDecision},
|
|
2254
|
+
* delivered over the transport's `onDecision` and applied DURABLY (by run id) on whatever engine
|
|
2255
|
+
* instance consumes it — even one that did not dispatch the turn — can never arrive ahead of its marker
|
|
2256
|
+
* or contend with a still-held lease and be dropped. A point-to-point broker can therefore hand the
|
|
2256
2257
|
* decision to any instance without it being dropped (the bug this design fixes).
|
|
2257
2258
|
*
|
|
2258
2259
|
* Recovery-safe: if the engine crashes (or a decision is genuinely lost because the worker died), the
|
|
@@ -2268,12 +2269,10 @@ declare class RemoteWorkflowExecutor implements WorkflowExecutor {
|
|
|
2268
2269
|
timeoutMs?: number;
|
|
2269
2270
|
});
|
|
2270
2271
|
/**
|
|
2271
|
-
*
|
|
2272
|
-
*
|
|
2272
|
+
* Enqueue one workflow turn under the engine-supplied `taskId`. Does NOT await the decision — the
|
|
2273
|
+
* engine has already suspended the run on `taskId` and applies the decision durably via `onDecision`.
|
|
2273
2274
|
*/
|
|
2274
|
-
dispatch(run: WorkflowRun, history: HistoryEvent[], pendingSignals?: WorkflowTask['pendingSignals']): Promise<
|
|
2275
|
-
taskId: string;
|
|
2276
|
-
}>;
|
|
2275
|
+
dispatch(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
2277
2276
|
}
|
|
2278
2277
|
|
|
2279
2278
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -802,17 +802,17 @@ interface WorkflowExecutor {
|
|
|
802
802
|
*/
|
|
803
803
|
advance?(run: WorkflowRun, history: HistoryEvent[], pendingSignals?: WorkflowTask['pendingSignals']): Promise<WorkflowDecision>;
|
|
804
804
|
/**
|
|
805
|
-
* DISPATCH-AND-SUSPEND (broker-backed, multi-instance safe):
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
805
|
+
* DISPATCH-AND-SUSPEND (broker-backed, multi-instance safe): enqueue the turn to a worker under the
|
|
806
|
+
* ENGINE-SUPPLIED `taskId`, WITHOUT awaiting the decision. The engine generates `taskId`, records it
|
|
807
|
+
* on the run as the awaited marker, AND releases the run's lease — all BEFORE calling this — so the
|
|
808
|
+
* worker's {@link WorkflowDecision} (delivered over {@link Transport.onDecision} and applied DURABLY
|
|
809
|
+
* by {@link WorkflowEngine.completeRemoteDecision}, which looks the run up by `decision.runId`) can
|
|
810
|
+
* never arrive ahead of its marker or contend with a still-held lease and be dropped. This method
|
|
811
|
+
* therefore ONLY enqueues — it owns no taskId generation and returns nothing. No in-memory await, so
|
|
812
|
+
* the decision is never lost to a point-to-point broker handing it to a non-dispatching instance.
|
|
813
|
+
* Provide this OR {@link advance} — exactly one.
|
|
814
|
+
*/
|
|
815
|
+
dispatch?(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
816
816
|
}
|
|
817
817
|
/**
|
|
818
818
|
* A transport in an ordered pool, identified by `id`. The engine dispatches on the first by default
|
|
@@ -2244,15 +2244,16 @@ declare function remoteStep<TInput, TOutput>(config: RemoteStepConfig<TInput, TO
|
|
|
2244
2244
|
|
|
2245
2245
|
/**
|
|
2246
2246
|
* A {@link WorkflowExecutor} backed by a {@link Transport}: it advances a remote workflow by
|
|
2247
|
-
* DISPATCHING a {@link WorkflowTask} over the broker
|
|
2247
|
+
* DISPATCHING a {@link WorkflowTask} over the broker under the ENGINE-SUPPLIED `taskId`, WITHOUT
|
|
2248
2248
|
* awaiting the decision. Pass one to `engine.registerRemote(name, version, { group, executor })` so a
|
|
2249
2249
|
* workflow authored in another SDK (e.g. the Python `durable-worker`) is driven over Redis/BullMQ.
|
|
2250
2250
|
*
|
|
2251
2251
|
* Multi-instance safe by construction: the executor holds NO in-memory state correlating a dispatched
|
|
2252
|
-
* turn to its decision. The engine
|
|
2253
|
-
* worker's {@link import('./interfaces').WorkflowDecision}
|
|
2254
|
-
* `onDecision` and applied DURABLY (by run id) on whatever engine
|
|
2255
|
-
*
|
|
2252
|
+
* turn to its decision. The engine records the `taskId` on the run as the awaited marker AND releases
|
|
2253
|
+
* the run's lease BEFORE calling `dispatch`, so the worker's {@link import('./interfaces').WorkflowDecision},
|
|
2254
|
+
* delivered over the transport's `onDecision` and applied DURABLY (by run id) on whatever engine
|
|
2255
|
+
* instance consumes it — even one that did not dispatch the turn — can never arrive ahead of its marker
|
|
2256
|
+
* or contend with a still-held lease and be dropped. A point-to-point broker can therefore hand the
|
|
2256
2257
|
* decision to any instance without it being dropped (the bug this design fixes).
|
|
2257
2258
|
*
|
|
2258
2259
|
* Recovery-safe: if the engine crashes (or a decision is genuinely lost because the worker died), the
|
|
@@ -2268,12 +2269,10 @@ declare class RemoteWorkflowExecutor implements WorkflowExecutor {
|
|
|
2268
2269
|
timeoutMs?: number;
|
|
2269
2270
|
});
|
|
2270
2271
|
/**
|
|
2271
|
-
*
|
|
2272
|
-
*
|
|
2272
|
+
* Enqueue one workflow turn under the engine-supplied `taskId`. Does NOT await the decision — the
|
|
2273
|
+
* engine has already suspended the run on `taskId` and applies the decision durably via `onDecision`.
|
|
2273
2274
|
*/
|
|
2274
|
-
dispatch(run: WorkflowRun, history: HistoryEvent[], pendingSignals?: WorkflowTask['pendingSignals']): Promise<
|
|
2275
|
-
taskId: string;
|
|
2276
|
-
}>;
|
|
2275
|
+
dispatch(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
2277
2276
|
}
|
|
2278
2277
|
|
|
2279
2278
|
/**
|
package/dist/index.js
CHANGED
|
@@ -701,7 +701,6 @@ function eventMatches(payload, match) {
|
|
|
701
701
|
__name(eventMatches, "eventMatches");
|
|
702
702
|
|
|
703
703
|
// src/remote-workflow-executor.ts
|
|
704
|
-
var taskCounter = 0;
|
|
705
704
|
var RemoteWorkflowExecutor = class {
|
|
706
705
|
static {
|
|
707
706
|
__name(this, "RemoteWorkflowExecutor");
|
|
@@ -713,15 +712,13 @@ var RemoteWorkflowExecutor = class {
|
|
|
713
712
|
this.group = group;
|
|
714
713
|
}
|
|
715
714
|
/**
|
|
716
|
-
*
|
|
717
|
-
*
|
|
715
|
+
* Enqueue one workflow turn under the engine-supplied `taskId`. Does NOT await the decision — the
|
|
716
|
+
* engine has already suspended the run on `taskId` and applies the decision durably via `onDecision`.
|
|
718
717
|
*/
|
|
719
|
-
async dispatch(run, history, pendingSignals) {
|
|
718
|
+
async dispatch(run, history, taskId, pendingSignals) {
|
|
720
719
|
if (!this.transport.dispatchWorkflowTask) {
|
|
721
720
|
throw new Error("transport does not support workflow tasks (dispatchWorkflowTask)");
|
|
722
721
|
}
|
|
723
|
-
taskCounter += 1;
|
|
724
|
-
const taskId = `${run.id}:wf:${taskCounter}`;
|
|
725
722
|
const task = {
|
|
726
723
|
taskId,
|
|
727
724
|
runId: run.id,
|
|
@@ -737,9 +734,6 @@ var RemoteWorkflowExecutor = class {
|
|
|
737
734
|
attempt: 1
|
|
738
735
|
};
|
|
739
736
|
await this.transport.dispatchWorkflowTask(task);
|
|
740
|
-
return {
|
|
741
|
-
taskId
|
|
742
|
-
};
|
|
743
737
|
}
|
|
744
738
|
};
|
|
745
739
|
|
|
@@ -2928,19 +2922,9 @@ var WorkflowEngine = class {
|
|
|
2928
2922
|
}
|
|
2929
2923
|
const history = await this.remoteHistory(run.id);
|
|
2930
2924
|
if (remote.executor.dispatch) {
|
|
2931
|
-
const
|
|
2925
|
+
const taskId = `${run.id}:wf:${globalThis.crypto.randomUUID().slice(0, 8)}`;
|
|
2932
2926
|
const silenceMs = this.remoteAdvanceSilenceMs;
|
|
2933
2927
|
const wakeAt = silenceMs != null ? this.clock() + silenceMs : void 0;
|
|
2934
|
-
const fresh = await this.store.getRun(run.id);
|
|
2935
|
-
if (fresh && (fresh.status === "cancelled" || fresh.status === "completed" || fresh.status === "dead")) {
|
|
2936
|
-
await this.store.releaseRunLock(run.id);
|
|
2937
|
-
return {
|
|
2938
|
-
runId: run.id,
|
|
2939
|
-
status: fresh.status,
|
|
2940
|
-
output: fresh.output,
|
|
2941
|
-
error: fresh.error
|
|
2942
|
-
};
|
|
2943
|
-
}
|
|
2944
2928
|
await this.store.updateRun(run.id, {
|
|
2945
2929
|
status: "suspended",
|
|
2946
2930
|
awaitingDecisionTaskId: taskId,
|
|
@@ -2953,6 +2937,7 @@ var WorkflowEngine = class {
|
|
|
2953
2937
|
workflow: run.workflow
|
|
2954
2938
|
});
|
|
2955
2939
|
await this.store.releaseRunLock(run.id);
|
|
2940
|
+
await remote.executor.dispatch(run, history, taskId);
|
|
2956
2941
|
return {
|
|
2957
2942
|
runId: run.id,
|
|
2958
2943
|
status: "suspended"
|