@dudousxd/nestjs-durable-core 0.85.2 → 0.85.3
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 +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +43 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5704,6 +5704,22 @@ declare class WorkflowEngine {
|
|
|
5704
5704
|
private markStarted;
|
|
5705
5705
|
private singletonWaitResult;
|
|
5706
5706
|
private execute;
|
|
5707
|
+
/**
|
|
5708
|
+
* Keep a wake that found `runId`'s lease held by a turn executing elsewhere, durably, so that turn
|
|
5709
|
+
* runs again once it ends instead of suspending on a snapshot that predates what the wake brought
|
|
5710
|
+
* (a signal, a child's completion). The request is a buffered signal on a token no workflow waits
|
|
5711
|
+
* on; the holder takes it after it releases the lease ({@link honorWakeRequests}).
|
|
5712
|
+
*
|
|
5713
|
+
* Written first and looked at second, against a holder that releases first and looks second:
|
|
5714
|
+
* whichever look runs last sees the other side's write. So when the run is no longer executing by
|
|
5715
|
+
* the time this re-reads it, the holder may have looked already, and this side takes the request
|
|
5716
|
+
* and wakes the run itself once the lease is free.
|
|
5717
|
+
*/
|
|
5718
|
+
private requestWakeAfterTurn;
|
|
5719
|
+
/** After a turn that suspended released its lease: run again if a wake was kept for it. */
|
|
5720
|
+
private honorWakeRequests;
|
|
5721
|
+
/** Take every wake request kept for `runId`; true when there was one. */
|
|
5722
|
+
private takeWakeRequests;
|
|
5707
5723
|
/**
|
|
5708
5724
|
* A wake that found the run leased by another instance is dropped, and normally that is fine: the
|
|
5709
5725
|
* holder's turn either sees what the wake wrote, or re-checks once it releases the lease
|
package/dist/index.d.ts
CHANGED
|
@@ -5704,6 +5704,22 @@ declare class WorkflowEngine {
|
|
|
5704
5704
|
private markStarted;
|
|
5705
5705
|
private singletonWaitResult;
|
|
5706
5706
|
private execute;
|
|
5707
|
+
/**
|
|
5708
|
+
* Keep a wake that found `runId`'s lease held by a turn executing elsewhere, durably, so that turn
|
|
5709
|
+
* runs again once it ends instead of suspending on a snapshot that predates what the wake brought
|
|
5710
|
+
* (a signal, a child's completion). The request is a buffered signal on a token no workflow waits
|
|
5711
|
+
* on; the holder takes it after it releases the lease ({@link honorWakeRequests}).
|
|
5712
|
+
*
|
|
5713
|
+
* Written first and looked at second, against a holder that releases first and looks second:
|
|
5714
|
+
* whichever look runs last sees the other side's write. So when the run is no longer executing by
|
|
5715
|
+
* the time this re-reads it, the holder may have looked already, and this side takes the request
|
|
5716
|
+
* and wakes the run itself once the lease is free.
|
|
5717
|
+
*/
|
|
5718
|
+
private requestWakeAfterTurn;
|
|
5719
|
+
/** After a turn that suspended released its lease: run again if a wake was kept for it. */
|
|
5720
|
+
private honorWakeRequests;
|
|
5721
|
+
/** Take every wake request kept for `runId`; true when there was one. */
|
|
5722
|
+
private takeWakeRequests;
|
|
5707
5723
|
/**
|
|
5708
5724
|
* A wake that found the run leased by another instance is dropped, and normally that is fine: the
|
|
5709
5725
|
* holder's turn either sees what the wake wrote, or re-checks once it releases the lease
|
package/dist/index.js
CHANGED
|
@@ -3824,7 +3824,6 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
3824
3824
|
}));
|
|
3825
3825
|
return unwrapCompletion(buffered.payload, `child "${id}"`);
|
|
3826
3826
|
}
|
|
3827
|
-
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
3828
3827
|
if (!existing) {
|
|
3829
3828
|
await writeCheckpoint(instantCheckpoint({
|
|
3830
3829
|
runId,
|
|
@@ -3834,6 +3833,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
3834
3833
|
status: "running"
|
|
3835
3834
|
}));
|
|
3836
3835
|
}
|
|
3836
|
+
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
3837
3837
|
throw new WorkflowSuspended(void 0, fanJoin([
|
|
3838
3838
|
{
|
|
3839
3839
|
waiterPrefix: `child:${id}`,
|
|
@@ -4452,6 +4452,7 @@ function deferred() {
|
|
|
4452
4452
|
__name(deferred, "deferred");
|
|
4453
4453
|
var pendingStateKey = /* @__PURE__ */ __name((at) => String(new Date(at).getTime()), "pendingStateKey");
|
|
4454
4454
|
var freshPendingKey = /* @__PURE__ */ __name(() => `${Date.now()}-${globalThis.crypto.randomUUID().slice(0, 8)}`, "freshPendingKey");
|
|
4455
|
+
var wakeRequestToken = /* @__PURE__ */ __name((runId) => `durable:wake-after-turn:${runId}`, "wakeRequestToken");
|
|
4455
4456
|
var CHILD_SIGNAL_PREFIX = "signal:child:";
|
|
4456
4457
|
var DELIVER_CHUNK = 50;
|
|
4457
4458
|
function childCompletion(child) {
|
|
@@ -7638,6 +7639,7 @@ var WorkflowEngine = class {
|
|
|
7638
7639
|
const lockNow = this.clock();
|
|
7639
7640
|
if (run.lockedBy !== this.instanceId || (run.lockedUntil ?? 0) <= lockNow) {
|
|
7640
7641
|
if (!await this.store.tryLockRun(run.id, this.instanceId, lockNow + this.leaseMs, lockNow)) {
|
|
7642
|
+
if (!this.leaseRetries.has(run.id)) this.inBackground(this.requestWakeAfterTurn(run.id));
|
|
7641
7643
|
this.recheckAfterLease(run.id, run.lockedUntil);
|
|
7642
7644
|
return {
|
|
7643
7645
|
runId: run.id,
|
|
@@ -7651,12 +7653,52 @@ var WorkflowEngine = class {
|
|
|
7651
7653
|
if (registered?.singleton && (result.status === "completed" || result.status === "failed" || result.status === "cancelled" || result.status === "dead")) {
|
|
7652
7654
|
void this.singletons.wakeNext(run).catch(() => void 0);
|
|
7653
7655
|
}
|
|
7656
|
+
if (result.status === "suspended") this.inBackground(this.honorWakeRequests(run.id));
|
|
7657
|
+
else if (TERMINAL_RUN_STATUSES.includes(result.status)) {
|
|
7658
|
+
this.inBackground(this.takeWakeRequests(run.id));
|
|
7659
|
+
}
|
|
7654
7660
|
return result;
|
|
7655
7661
|
} finally {
|
|
7656
7662
|
held.stop();
|
|
7657
7663
|
}
|
|
7658
7664
|
}
|
|
7659
7665
|
/**
|
|
7666
|
+
* Keep a wake that found `runId`'s lease held by a turn executing elsewhere, durably, so that turn
|
|
7667
|
+
* runs again once it ends instead of suspending on a snapshot that predates what the wake brought
|
|
7668
|
+
* (a signal, a child's completion). The request is a buffered signal on a token no workflow waits
|
|
7669
|
+
* on; the holder takes it after it releases the lease ({@link honorWakeRequests}).
|
|
7670
|
+
*
|
|
7671
|
+
* Written first and looked at second, against a holder that releases first and looks second:
|
|
7672
|
+
* whichever look runs last sees the other side's write. So when the run is no longer executing by
|
|
7673
|
+
* the time this re-reads it, the holder may have looked already, and this side takes the request
|
|
7674
|
+
* and wakes the run itself once the lease is free.
|
|
7675
|
+
*/
|
|
7676
|
+
async requestWakeAfterTurn(runId) {
|
|
7677
|
+
await this.store.bufferSignal(wakeRequestToken(runId), null);
|
|
7678
|
+
const run = await this.store.getRun(runId);
|
|
7679
|
+
if (run?.status === "running") return;
|
|
7680
|
+
if (!run) {
|
|
7681
|
+
await this.takeWakeRequests(runId);
|
|
7682
|
+
return;
|
|
7683
|
+
}
|
|
7684
|
+
if (!await this.takeWakeRequests(runId)) return;
|
|
7685
|
+
if (TERMINAL_RUN_STATUSES.includes(run.status)) return;
|
|
7686
|
+
this.recheckAfterLease(runId, run.lockedUntil);
|
|
7687
|
+
}
|
|
7688
|
+
/** After a turn that suspended released its lease: run again if a wake was kept for it. */
|
|
7689
|
+
async honorWakeRequests(runId) {
|
|
7690
|
+
if (!await this.takeWakeRequests(runId)) return;
|
|
7691
|
+
await this.wake(runId).catch((err) => {
|
|
7692
|
+
if (!(err instanceof NamespaceMismatch)) throw err;
|
|
7693
|
+
});
|
|
7694
|
+
}
|
|
7695
|
+
/** Take every wake request kept for `runId`; true when there was one. */
|
|
7696
|
+
async takeWakeRequests(runId) {
|
|
7697
|
+
let taken = false;
|
|
7698
|
+
while (await this.store.takeBufferedSignal(wakeRequestToken(runId))) taken = true;
|
|
7699
|
+
return taken;
|
|
7700
|
+
}
|
|
7701
|
+
/**
|
|
7660
7702
|
* A wake that found the run leased by another instance is dropped, and normally that is fine: the
|
|
7661
7703
|
* holder's turn either sees what the wake wrote, or re-checks once it releases the lease
|
|
7662
7704
|
* ({@link redriveSettledSteps}, {@link redriveSettledChildren}). Not if the holder goes down first
|