@dudousxd/nestjs-durable-core 0.72.0 → 0.72.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 +135 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -1
- package/dist/index.d.ts +63 -1
- package/dist/index.js +131 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
InMemoryTransport: () => InMemoryTransport,
|
|
47
47
|
LEGACY_V1_CAPABILITIES: () => LEGACY_V1_CAPABILITIES,
|
|
48
48
|
LEGACY_V1_PROTOCOL: () => LEGACY_V1_PROTOCOL,
|
|
49
|
+
NestedWorkflowCallError: () => NestedWorkflowCallError,
|
|
49
50
|
NonDeterminismError: () => NonDeterminismError,
|
|
50
51
|
QueueController: () => QueueController,
|
|
51
52
|
RUN_VALUE_FACET_LIMIT: () => RUN_VALUE_FACET_LIMIT,
|
|
@@ -92,6 +93,7 @@ __export(index_exports, {
|
|
|
92
93
|
coveredTokens: () => coveredTokens,
|
|
93
94
|
createStepLogger: () => createStepLogger,
|
|
94
95
|
currentStep: () => currentStep,
|
|
96
|
+
currentStepScope: () => currentStepScope,
|
|
95
97
|
currentWorkflowCtx: () => currentWorkflowCtx,
|
|
96
98
|
debug: () => debug,
|
|
97
99
|
describeWorker: () => describeWorker,
|
|
@@ -133,7 +135,9 @@ __export(index_exports, {
|
|
|
133
135
|
resolveRunWaiting: () => resolveRunWaiting,
|
|
134
136
|
runDurableExecution: () => runDurableExecution,
|
|
135
137
|
runInStepLogger: () => runInStepLogger,
|
|
138
|
+
runInStepScope: () => runInStepScope,
|
|
136
139
|
runInWorkflowCtx: () => runInWorkflowCtx,
|
|
140
|
+
runOutsideWorkflowCtx: () => runOutsideWorkflowCtx,
|
|
137
141
|
runSchedules: () => runSchedules,
|
|
138
142
|
runStepHandler: () => runStepHandler,
|
|
139
143
|
runValueFacetsFromRuns: () => runValueFacetsFromRuns,
|
|
@@ -324,6 +328,27 @@ function currentWorkflowCtx() {
|
|
|
324
328
|
return storage.getStore();
|
|
325
329
|
}
|
|
326
330
|
__name(currentWorkflowCtx, "currentWorkflowCtx");
|
|
331
|
+
var STEP_SCOPE_KEY = Symbol.for("nestjs-durable:ambient-step-scope");
|
|
332
|
+
var stepScopeRef = globalThis;
|
|
333
|
+
if (!stepScopeRef[STEP_SCOPE_KEY]) {
|
|
334
|
+
stepScopeRef[STEP_SCOPE_KEY] = new import_node_async_hooks.AsyncLocalStorage();
|
|
335
|
+
}
|
|
336
|
+
var stepScopeStorage = stepScopeRef[STEP_SCOPE_KEY];
|
|
337
|
+
function runInStepScope(owner, step, fn) {
|
|
338
|
+
return stepScopeStorage.run({
|
|
339
|
+
owner,
|
|
340
|
+
step
|
|
341
|
+
}, fn);
|
|
342
|
+
}
|
|
343
|
+
__name(runInStepScope, "runInStepScope");
|
|
344
|
+
function currentStepScope() {
|
|
345
|
+
return stepScopeStorage.getStore();
|
|
346
|
+
}
|
|
347
|
+
__name(currentStepScope, "currentStepScope");
|
|
348
|
+
function runOutsideWorkflowCtx(fn) {
|
|
349
|
+
return storage.exit(() => stepScopeStorage.exit(fn));
|
|
350
|
+
}
|
|
351
|
+
__name(runOutsideWorkflowCtx, "runOutsideWorkflowCtx");
|
|
327
352
|
|
|
328
353
|
// src/ambient-step.ts
|
|
329
354
|
var import_node_async_hooks2 = require("async_hooks");
|
|
@@ -486,6 +511,21 @@ var NonDeterminismError = class extends Error {
|
|
|
486
511
|
this.seq = seq;
|
|
487
512
|
}
|
|
488
513
|
};
|
|
514
|
+
var NestedWorkflowCallError = class extends FatalError {
|
|
515
|
+
static {
|
|
516
|
+
__name(this, "NestedWorkflowCallError");
|
|
517
|
+
}
|
|
518
|
+
runId;
|
|
519
|
+
primitive;
|
|
520
|
+
step;
|
|
521
|
+
constructor(runId, primitive, step) {
|
|
522
|
+
super(`ctx.${primitive}() was called inside the body of step "${step}" (run ${runId}). Workflow primitives (child/startChild/step/sleep/signals/sideEffect/\u2026, and MyWorkflow.start()/.execute() via the ambient ctx) must be called from the workflow body, never from inside a step body: the step's checkpoint replays without re-running it, so the nested call would shift every later journal position and corrupt the run on replay. Move the call out of the step.`, "nested_workflow_call");
|
|
523
|
+
this.name = "NestedWorkflowCallError";
|
|
524
|
+
this.runId = runId;
|
|
525
|
+
this.primitive = primitive;
|
|
526
|
+
this.step = step;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
489
529
|
var GatherError = class extends Error {
|
|
490
530
|
static {
|
|
491
531
|
__name(this, "GatherError");
|
|
@@ -842,14 +882,19 @@ async function runStepHandler(task, handler) {
|
|
|
842
882
|
} : result, "withEvents");
|
|
843
883
|
try {
|
|
844
884
|
const logger = createStepLogger(events, Date.now);
|
|
845
|
-
const output = await runDurableExecution(
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
885
|
+
const output = await runDurableExecution(
|
|
886
|
+
{
|
|
887
|
+
unit: "step",
|
|
888
|
+
runId: task.runId,
|
|
889
|
+
workflow: void 0,
|
|
890
|
+
name: task.name,
|
|
891
|
+
seq: task.seq,
|
|
892
|
+
attempt: task.attempt
|
|
893
|
+
},
|
|
894
|
+
// Outside any ambient workflow ctx: an in-process transport runs the handler on the parent
|
|
895
|
+
// body's async path, but a handler is not the body (see `runOutsideWorkflowCtx`).
|
|
896
|
+
async () => runOutsideWorkflowCtx(() => runInStepLogger(logger, () => handler(task.input, logger)))
|
|
897
|
+
);
|
|
853
898
|
return withEvents({
|
|
854
899
|
...base,
|
|
855
900
|
status: "completed",
|
|
@@ -2753,10 +2798,15 @@ var Position = class Position2 {
|
|
|
2753
2798
|
rewind() {
|
|
2754
2799
|
this.seq -= 1;
|
|
2755
2800
|
}
|
|
2801
|
+
/** The position the NEXT primitive would claim, without claiming it. */
|
|
2802
|
+
peek() {
|
|
2803
|
+
return this.seq + 1;
|
|
2804
|
+
}
|
|
2756
2805
|
};
|
|
2757
2806
|
function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttributesSchema) {
|
|
2758
2807
|
const { store, replay } = host;
|
|
2759
2808
|
const pos = new Position();
|
|
2809
|
+
const scopeOwner = {};
|
|
2760
2810
|
const readCheckpoint = /* @__PURE__ */ __name((seq) => {
|
|
2761
2811
|
const hit = replay?.get(seq);
|
|
2762
2812
|
if (hit !== void 0) return hit;
|
|
@@ -2802,7 +2852,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
2802
2852
|
};
|
|
2803
2853
|
const body = /* @__PURE__ */ __name(() => {
|
|
2804
2854
|
const logger = createStepLogger(events, host.clock);
|
|
2805
|
-
return runInStepLogger(logger, () => fn(logger));
|
|
2855
|
+
return runInStepScope(scopeOwner, name, () => runInStepLogger(logger, () => fn(logger)));
|
|
2806
2856
|
}, "body");
|
|
2807
2857
|
const output = host.interceptStep ? await host.interceptStep(invocation, body) : await body();
|
|
2808
2858
|
await host.completeStep({
|
|
@@ -2855,7 +2905,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
2855
2905
|
}
|
|
2856
2906
|
if (existing && existing.status === "completed") return existing.output;
|
|
2857
2907
|
return store.transaction(async (tx) => {
|
|
2858
|
-
const output = await fn(tx.raw);
|
|
2908
|
+
const output = await runInStepScope(scopeOwner, name, () => fn(tx.raw));
|
|
2859
2909
|
const cp = instantCheckpoint({
|
|
2860
2910
|
runId,
|
|
2861
2911
|
seq: current,
|
|
@@ -3364,30 +3414,49 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
3364
3414
|
});
|
|
3365
3415
|
}
|
|
3366
3416
|
__name(step, "step");
|
|
3417
|
+
const nestedStep = /* @__PURE__ */ __name(() => {
|
|
3418
|
+
const scope = currentStepScope();
|
|
3419
|
+
return scope !== void 0 && scope.owner === scopeOwner ? scope.step : void 0;
|
|
3420
|
+
}, "nestedStep");
|
|
3421
|
+
const guard = /* @__PURE__ */ __name((primitive, fn) => (...args) => {
|
|
3422
|
+
const stepName = nestedStep();
|
|
3423
|
+
if (stepName === void 0) return fn(...args);
|
|
3424
|
+
return (async () => {
|
|
3425
|
+
if (await readCheckpoint(pos.peek())) return fn(...args);
|
|
3426
|
+
throw new NestedWorkflowCallError(runId, primitive, stepName);
|
|
3427
|
+
})();
|
|
3428
|
+
}, "guard");
|
|
3429
|
+
const guardedWebhook = /* @__PURE__ */ __name(() => {
|
|
3430
|
+
const stepName = nestedStep();
|
|
3431
|
+
if (stepName !== void 0 && !replay?.get(pos.peek())) {
|
|
3432
|
+
throw new NestedWorkflowCallError(runId, "webhook", stepName);
|
|
3433
|
+
}
|
|
3434
|
+
return webhook();
|
|
3435
|
+
}, "guardedWebhook");
|
|
3367
3436
|
return {
|
|
3368
3437
|
runId,
|
|
3369
|
-
step,
|
|
3370
|
-
localStep,
|
|
3371
|
-
upsertSearchAttributes,
|
|
3372
|
-
transaction,
|
|
3373
|
-
callEntity,
|
|
3374
|
-
signalEntity,
|
|
3375
|
-
sleep,
|
|
3376
|
-
sleepUntil,
|
|
3438
|
+
step: guard("step", step),
|
|
3439
|
+
localStep: guard("localStep", localStep),
|
|
3440
|
+
upsertSearchAttributes: guard("upsertSearchAttributes", upsertSearchAttributes),
|
|
3441
|
+
transaction: guard("transaction", transaction),
|
|
3442
|
+
callEntity: guard("callEntity", callEntity),
|
|
3443
|
+
signalEntity: guard("signalEntity", signalEntity),
|
|
3444
|
+
sleep: guard("sleep", sleep),
|
|
3445
|
+
sleepUntil: guard("sleepUntil", sleepUntil),
|
|
3377
3446
|
continueAsNew,
|
|
3378
|
-
waitForSignal,
|
|
3379
|
-
waitForEvent,
|
|
3380
|
-
task,
|
|
3381
|
-
child,
|
|
3382
|
-
all,
|
|
3383
|
-
startChild,
|
|
3384
|
-
breakpoint,
|
|
3385
|
-
webhook,
|
|
3386
|
-
setEvent,
|
|
3387
|
-
onUpdate,
|
|
3388
|
-
patched,
|
|
3389
|
-
now,
|
|
3390
|
-
sideEffect
|
|
3447
|
+
waitForSignal: guard("waitForSignal", waitForSignal),
|
|
3448
|
+
waitForEvent: guard("waitForEvent", waitForEvent),
|
|
3449
|
+
task: guard("task", task),
|
|
3450
|
+
child: guard("child", child),
|
|
3451
|
+
all: guard("all", all),
|
|
3452
|
+
startChild: guard("startChild", startChild),
|
|
3453
|
+
breakpoint: guard("breakpoint", breakpoint),
|
|
3454
|
+
webhook: guardedWebhook,
|
|
3455
|
+
setEvent: guard("setEvent", setEvent),
|
|
3456
|
+
onUpdate: guard("onUpdate", onUpdate),
|
|
3457
|
+
patched: guard("patched", patched),
|
|
3458
|
+
now: guard("now", now),
|
|
3459
|
+
sideEffect: guard("sideEffect", sideEffect)
|
|
3391
3460
|
};
|
|
3392
3461
|
}
|
|
3393
3462
|
__name(createWorkflowCtx, "createWorkflowCtx");
|
|
@@ -3989,10 +4058,30 @@ var WorkflowEngine = class {
|
|
|
3989
4058
|
getRun(runId) {
|
|
3990
4059
|
return this.store.getRun(runId);
|
|
3991
4060
|
}
|
|
3992
|
-
|
|
4061
|
+
/**
|
|
4062
|
+
* Re-execute a run's body (replaying its checkpoints). This is the EXPLICIT entry point: besides
|
|
4063
|
+
* driving a live run, it re-drives a `failed` run — the manual retry (prefer {@link requeue}, which
|
|
4064
|
+
* also resets the failure state so replay re-attempts the failed parts). Completed / cancelled /
|
|
4065
|
+
* dead runs are never re-executed. The engine's own implicit wake-ups (signals, step results,
|
|
4066
|
+
* timers, redelivered dispatches) go through {@link resumeImplicit}, which treats `failed` as
|
|
4067
|
+
* terminal too.
|
|
4068
|
+
*/
|
|
4069
|
+
resume(runId) {
|
|
4070
|
+
return this.resumeRun(runId, true);
|
|
4071
|
+
}
|
|
4072
|
+
/**
|
|
4073
|
+
* {@link resume} for every IMPLICIT wake-up — a delivered signal/child completion, a late step
|
|
4074
|
+
* result, a due timer, a redelivered dispatch, a queue-slot wake. A `failed` run is terminal to
|
|
4075
|
+
* these: only an explicit retry ({@link requeue} / {@link resume}) may re-drive it. Otherwise a
|
|
4076
|
+
* stale waiter or a late result left behind by a failed run silently re-executes its body.
|
|
4077
|
+
*/
|
|
4078
|
+
resumeImplicit(runId) {
|
|
4079
|
+
return this.resumeRun(runId, false);
|
|
4080
|
+
}
|
|
4081
|
+
async resumeRun(runId, allowFailed) {
|
|
3993
4082
|
const run = await this.store.getRun(runId);
|
|
3994
4083
|
if (!run) throw new Error(`run ${runId} not found`);
|
|
3995
|
-
if (run.status === "cancelled" || run.status === "completed" || run.status === "dead") {
|
|
4084
|
+
if (run.status === "cancelled" || run.status === "completed" || run.status === "dead" || run.status === "failed" && !allowFailed) {
|
|
3996
4085
|
return {
|
|
3997
4086
|
runId,
|
|
3998
4087
|
status: run.status,
|
|
@@ -4441,7 +4530,7 @@ var WorkflowEngine = class {
|
|
|
4441
4530
|
const nowMs = this.clock();
|
|
4442
4531
|
const acquired = await this.store.tryLockRun(runId, this.instanceId, nowMs + this.leaseMs, nowMs);
|
|
4443
4532
|
if (!acquired) return null;
|
|
4444
|
-
return this.
|
|
4533
|
+
return this.resumeImplicit(runId).catch((err) => {
|
|
4445
4534
|
if (err instanceof NamespaceMismatch) return null;
|
|
4446
4535
|
throw err;
|
|
4447
4536
|
});
|
|
@@ -4662,7 +4751,7 @@ var WorkflowEngine = class {
|
|
|
4662
4751
|
if (!acquired) continue;
|
|
4663
4752
|
try {
|
|
4664
4753
|
const settled = onLocked ? await onLocked(run) : void 0;
|
|
4665
|
-
results.push(settled ?? await this.
|
|
4754
|
+
results.push(settled ?? await this.resumeImplicit(run.id));
|
|
4666
4755
|
} catch (error2) {
|
|
4667
4756
|
console.error(`[nestjs-durable] could not resume run ${run.id} (${run.workflow}@${run.workflowVersion}); leaving it for another instance:`, error2);
|
|
4668
4757
|
}
|
|
@@ -4759,7 +4848,7 @@ var WorkflowEngine = class {
|
|
|
4759
4848
|
// for an ordinary (non-fan) signal/child await.
|
|
4760
4849
|
parallelGroup: waiter.parallelGroup
|
|
4761
4850
|
}));
|
|
4762
|
-
return this.
|
|
4851
|
+
return this.resumeImplicit(waiter.runId).catch((err) => {
|
|
4763
4852
|
if (err instanceof NamespaceMismatch) return null;
|
|
4764
4853
|
throw err;
|
|
4765
4854
|
});
|
|
@@ -4875,7 +4964,7 @@ var WorkflowEngine = class {
|
|
|
4875
4964
|
async cancel(runId, opts) {
|
|
4876
4965
|
const run = await this.store.getRun(runId);
|
|
4877
4966
|
if (!run) return null;
|
|
4878
|
-
if (
|
|
4967
|
+
if (TERMINAL_RUN_STATUSES.includes(run.status)) {
|
|
4879
4968
|
return {
|
|
4880
4969
|
runId,
|
|
4881
4970
|
status: run.status,
|
|
@@ -4904,7 +4993,7 @@ var WorkflowEngine = class {
|
|
|
4904
4993
|
}).catch(() => void 0);
|
|
4905
4994
|
}
|
|
4906
4995
|
queueMicrotask(() => {
|
|
4907
|
-
void this.
|
|
4996
|
+
void this.resumeImplicit(runId).then(() => this.notifyCancelled(runId)).catch(() => void 0);
|
|
4908
4997
|
});
|
|
4909
4998
|
await this.cancelChildren(runId, opts);
|
|
4910
4999
|
return {
|
|
@@ -5739,7 +5828,7 @@ var WorkflowEngine = class {
|
|
|
5739
5828
|
const checkpoint = await this.store.getCheckpoint(runId, cmd.seq);
|
|
5740
5829
|
if (checkpoint && checkpoint.status !== "pending") {
|
|
5741
5830
|
setTimeout(() => {
|
|
5742
|
-
void this.
|
|
5831
|
+
void this.resumeImplicit(runId).catch(() => void 0);
|
|
5743
5832
|
}, 0).unref?.();
|
|
5744
5833
|
return;
|
|
5745
5834
|
}
|
|
@@ -6081,7 +6170,7 @@ var WorkflowEngine = class {
|
|
|
6081
6170
|
kind: "signal",
|
|
6082
6171
|
output: payload
|
|
6083
6172
|
}));
|
|
6084
|
-
setTimeout(() => void this.
|
|
6173
|
+
setTimeout(() => void this.resumeImplicit(run.id).catch(() => void 0), 0);
|
|
6085
6174
|
}, "deliverBuffered");
|
|
6086
6175
|
const buffered = await this.store.takeBufferedSignal(cmd.signal);
|
|
6087
6176
|
if (buffered) {
|
|
@@ -6895,7 +6984,7 @@ var WorkflowEngine = class {
|
|
|
6895
6984
|
queueMs: startedAt.getTime() - cp.enqueuedAt.getTime(),
|
|
6896
6985
|
durationMs: finishedAt.getTime() - startedAt.getTime()
|
|
6897
6986
|
});
|
|
6898
|
-
await this.
|
|
6987
|
+
await this.resumeImplicit(result.runId).catch((err) => {
|
|
6899
6988
|
if (err instanceof NamespaceMismatch) return null;
|
|
6900
6989
|
throw err;
|
|
6901
6990
|
});
|
|
@@ -6996,7 +7085,7 @@ var WorkflowEngine = class {
|
|
|
6996
7085
|
...waiters
|
|
6997
7086
|
];
|
|
6998
7087
|
waiters.clear();
|
|
6999
|
-
for (const runId of runIds) void this.
|
|
7088
|
+
for (const runId of runIds) void this.resumeImplicit(runId).catch(() => void 0);
|
|
7000
7089
|
}
|
|
7001
7090
|
/** Release the flow-control slot a dispatched step held (if any), by its stepId. */
|
|
7002
7091
|
async releaseQueueSlot(id) {
|
|
@@ -8149,6 +8238,7 @@ var InMemoryTransport = class {
|
|
|
8149
8238
|
InMemoryTransport,
|
|
8150
8239
|
LEGACY_V1_CAPABILITIES,
|
|
8151
8240
|
LEGACY_V1_PROTOCOL,
|
|
8241
|
+
NestedWorkflowCallError,
|
|
8152
8242
|
NonDeterminismError,
|
|
8153
8243
|
QueueController,
|
|
8154
8244
|
RUN_VALUE_FACET_LIMIT,
|
|
@@ -8195,6 +8285,7 @@ var InMemoryTransport = class {
|
|
|
8195
8285
|
coveredTokens,
|
|
8196
8286
|
createStepLogger,
|
|
8197
8287
|
currentStep,
|
|
8288
|
+
currentStepScope,
|
|
8198
8289
|
currentWorkflowCtx,
|
|
8199
8290
|
debug,
|
|
8200
8291
|
describeWorker,
|
|
@@ -8236,7 +8327,9 @@ var InMemoryTransport = class {
|
|
|
8236
8327
|
resolveRunWaiting,
|
|
8237
8328
|
runDurableExecution,
|
|
8238
8329
|
runInStepLogger,
|
|
8330
|
+
runInStepScope,
|
|
8239
8331
|
runInWorkflowCtx,
|
|
8332
|
+
runOutsideWorkflowCtx,
|
|
8240
8333
|
runSchedules,
|
|
8241
8334
|
runStepHandler,
|
|
8242
8335
|
runValueFacetsFromRuns,
|