@dudousxd/nestjs-durable-core 0.85.2 → 0.85.4
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 +43 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -5
- package/dist/index.d.ts +22 -5
- package/dist/index.js +43 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4037,7 +4037,6 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
4037
4037
|
}));
|
|
4038
4038
|
return unwrapCompletion(buffered.payload, `child "${id}"`);
|
|
4039
4039
|
}
|
|
4040
|
-
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
4041
4040
|
if (!existing) {
|
|
4042
4041
|
await writeCheckpoint(instantCheckpoint({
|
|
4043
4042
|
runId,
|
|
@@ -4047,6 +4046,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
4047
4046
|
status: "running"
|
|
4048
4047
|
}));
|
|
4049
4048
|
}
|
|
4049
|
+
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
4050
4050
|
throw new WorkflowSuspended(void 0, fanJoin([
|
|
4051
4051
|
{
|
|
4052
4052
|
waiterPrefix: `child:${id}`,
|
|
@@ -4665,6 +4665,7 @@ function deferred() {
|
|
|
4665
4665
|
__name(deferred, "deferred");
|
|
4666
4666
|
var pendingStateKey = /* @__PURE__ */ __name((at) => String(new Date(at).getTime()), "pendingStateKey");
|
|
4667
4667
|
var freshPendingKey = /* @__PURE__ */ __name(() => `${Date.now()}-${globalThis.crypto.randomUUID().slice(0, 8)}`, "freshPendingKey");
|
|
4668
|
+
var wakeRequestToken = /* @__PURE__ */ __name((runId) => `durable:wake-after-turn:${runId}`, "wakeRequestToken");
|
|
4668
4669
|
var CHILD_SIGNAL_PREFIX = "signal:child:";
|
|
4669
4670
|
var DELIVER_CHUNK = 50;
|
|
4670
4671
|
function childCompletion(child) {
|
|
@@ -7851,6 +7852,7 @@ var WorkflowEngine = class {
|
|
|
7851
7852
|
const lockNow = this.clock();
|
|
7852
7853
|
if (run.lockedBy !== this.instanceId || (run.lockedUntil ?? 0) <= lockNow) {
|
|
7853
7854
|
if (!await this.store.tryLockRun(run.id, this.instanceId, lockNow + this.leaseMs, lockNow)) {
|
|
7855
|
+
if (!this.leaseRetries.has(run.id)) this.inBackground(this.requestWakeAfterTurn(run.id));
|
|
7854
7856
|
this.recheckAfterLease(run.id, run.lockedUntil);
|
|
7855
7857
|
return {
|
|
7856
7858
|
runId: run.id,
|
|
@@ -7864,12 +7866,52 @@ var WorkflowEngine = class {
|
|
|
7864
7866
|
if (registered?.singleton && (result.status === "completed" || result.status === "failed" || result.status === "cancelled" || result.status === "dead")) {
|
|
7865
7867
|
void this.singletons.wakeNext(run).catch(() => void 0);
|
|
7866
7868
|
}
|
|
7869
|
+
if (result.status === "suspended") this.inBackground(this.honorWakeRequests(run.id));
|
|
7870
|
+
else if (TERMINAL_RUN_STATUSES.includes(result.status)) {
|
|
7871
|
+
this.inBackground(this.takeWakeRequests(run.id));
|
|
7872
|
+
}
|
|
7867
7873
|
return result;
|
|
7868
7874
|
} finally {
|
|
7869
7875
|
held.stop();
|
|
7870
7876
|
}
|
|
7871
7877
|
}
|
|
7872
7878
|
/**
|
|
7879
|
+
* Keep a wake that found `runId`'s lease held by a turn executing elsewhere, durably, so that turn
|
|
7880
|
+
* runs again once it ends instead of suspending on a snapshot that predates what the wake brought
|
|
7881
|
+
* (a signal, a child's completion). The request is a buffered signal on a token no workflow waits
|
|
7882
|
+
* on; the holder takes it after it releases the lease ({@link honorWakeRequests}).
|
|
7883
|
+
*
|
|
7884
|
+
* Written first and looked at second, against a holder that releases first and looks second:
|
|
7885
|
+
* whichever look runs last sees the other side's write. So when the run is no longer executing by
|
|
7886
|
+
* the time this re-reads it, the holder may have looked already, and this side takes the request
|
|
7887
|
+
* and wakes the run itself once the lease is free.
|
|
7888
|
+
*/
|
|
7889
|
+
async requestWakeAfterTurn(runId) {
|
|
7890
|
+
await this.store.bufferSignal(wakeRequestToken(runId), null);
|
|
7891
|
+
const run = await this.store.getRun(runId);
|
|
7892
|
+
if (run?.status === "running") return;
|
|
7893
|
+
if (!run) {
|
|
7894
|
+
await this.takeWakeRequests(runId);
|
|
7895
|
+
return;
|
|
7896
|
+
}
|
|
7897
|
+
if (!await this.takeWakeRequests(runId)) return;
|
|
7898
|
+
if (TERMINAL_RUN_STATUSES.includes(run.status)) return;
|
|
7899
|
+
this.recheckAfterLease(runId, run.lockedUntil);
|
|
7900
|
+
}
|
|
7901
|
+
/** After a turn that suspended released its lease: run again if a wake was kept for it. */
|
|
7902
|
+
async honorWakeRequests(runId) {
|
|
7903
|
+
if (!await this.takeWakeRequests(runId)) return;
|
|
7904
|
+
await this.wake(runId).catch((err) => {
|
|
7905
|
+
if (!(err instanceof NamespaceMismatch)) throw err;
|
|
7906
|
+
});
|
|
7907
|
+
}
|
|
7908
|
+
/** Take every wake request kept for `runId`; true when there was one. */
|
|
7909
|
+
async takeWakeRequests(runId) {
|
|
7910
|
+
let taken = false;
|
|
7911
|
+
while (await this.store.takeBufferedSignal(wakeRequestToken(runId))) taken = true;
|
|
7912
|
+
return taken;
|
|
7913
|
+
}
|
|
7914
|
+
/**
|
|
7873
7915
|
* A wake that found the run leased by another instance is dropped, and normally that is fine: the
|
|
7874
7916
|
* holder's turn either sees what the wake wrote, or re-checks once it releases the lease
|
|
7875
7917
|
* ({@link redriveSettledSteps}, {@link redriveSettledChildren}). Not if the holder goes down first
|