@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.d.cts
CHANGED
|
@@ -947,12 +947,13 @@ interface WorkflowRun {
|
|
|
947
947
|
* from the creating engine. It is DERIVED, never caller input: `StartOptions` has no `origin`, so
|
|
948
948
|
* nothing a caller passes to `start` can make a run claim another lib's name.
|
|
949
949
|
*
|
|
950
|
-
* `undefined` means
|
|
950
|
+
* `undefined` means NO package origin — the console labels that bucket `app` (the app's own
|
|
951
|
+
* workflows, not declared by any library). It is what you get for a run created before this
|
|
951
952
|
* field existed, for a registration path that carries no origin (`registerRemote`, convention
|
|
952
953
|
* routing, a synthesized remote child, or a bare `engine.register` with no `origin` option), and
|
|
953
954
|
* for a workflow whose declaring package could not be resolved with confidence. A wrong origin is
|
|
954
955
|
* worse than an absent one: a filter that silently drops runs looks exactly like runs that never
|
|
955
|
-
* existed, so callers must
|
|
956
|
+
* existed, so callers must keep the no-origin bucket distinct and never fold it into a real package.
|
|
956
957
|
*/
|
|
957
958
|
origin?: string | undefined;
|
|
958
959
|
/**
|
|
@@ -1747,11 +1748,11 @@ interface RunQuery {
|
|
|
1747
1748
|
* Restrict to runs whose workflow was declared by this package (exact match against
|
|
1748
1749
|
* {@link WorkflowRun.origin}), ANDed with the other predicates.
|
|
1749
1750
|
*
|
|
1750
|
-
* A run with NO origin (
|
|
1751
|
+
* A run with NO origin (the console's `app` bucket — see the field) matches no `origin` VALUE at all, so a UI facet
|
|
1751
1752
|
* built on this must keep an "all origins" option: filtering by any single package silently hides
|
|
1752
1753
|
* every unattributed run, which reads to an operator as "those runs do not exist". `null` selects
|
|
1753
|
-
* exactly that absent bucket (`origin IS NULL`), so a paginated console can offer an
|
|
1754
|
-
* facet without having to hold every run in the browser to find them.
|
|
1754
|
+
* exactly that absent bucket (`origin IS NULL`), so a paginated console can offer an `app`
|
|
1755
|
+
* (no-origin) facet without having to hold every run in the browser to find them.
|
|
1755
1756
|
*/
|
|
1756
1757
|
origin?: string | null | undefined;
|
|
1757
1758
|
/**
|
|
@@ -5704,6 +5705,22 @@ declare class WorkflowEngine {
|
|
|
5704
5705
|
private markStarted;
|
|
5705
5706
|
private singletonWaitResult;
|
|
5706
5707
|
private execute;
|
|
5708
|
+
/**
|
|
5709
|
+
* Keep a wake that found `runId`'s lease held by a turn executing elsewhere, durably, so that turn
|
|
5710
|
+
* runs again once it ends instead of suspending on a snapshot that predates what the wake brought
|
|
5711
|
+
* (a signal, a child's completion). The request is a buffered signal on a token no workflow waits
|
|
5712
|
+
* on; the holder takes it after it releases the lease ({@link honorWakeRequests}).
|
|
5713
|
+
*
|
|
5714
|
+
* Written first and looked at second, against a holder that releases first and looks second:
|
|
5715
|
+
* whichever look runs last sees the other side's write. So when the run is no longer executing by
|
|
5716
|
+
* the time this re-reads it, the holder may have looked already, and this side takes the request
|
|
5717
|
+
* and wakes the run itself once the lease is free.
|
|
5718
|
+
*/
|
|
5719
|
+
private requestWakeAfterTurn;
|
|
5720
|
+
/** After a turn that suspended released its lease: run again if a wake was kept for it. */
|
|
5721
|
+
private honorWakeRequests;
|
|
5722
|
+
/** Take every wake request kept for `runId`; true when there was one. */
|
|
5723
|
+
private takeWakeRequests;
|
|
5707
5724
|
/**
|
|
5708
5725
|
* A wake that found the run leased by another instance is dropped, and normally that is fine: the
|
|
5709
5726
|
* holder's turn either sees what the wake wrote, or re-checks once it releases the lease
|
package/dist/index.d.ts
CHANGED
|
@@ -947,12 +947,13 @@ interface WorkflowRun {
|
|
|
947
947
|
* from the creating engine. It is DERIVED, never caller input: `StartOptions` has no `origin`, so
|
|
948
948
|
* nothing a caller passes to `start` can make a run claim another lib's name.
|
|
949
949
|
*
|
|
950
|
-
* `undefined` means
|
|
950
|
+
* `undefined` means NO package origin — the console labels that bucket `app` (the app's own
|
|
951
|
+
* workflows, not declared by any library). It is what you get for a run created before this
|
|
951
952
|
* field existed, for a registration path that carries no origin (`registerRemote`, convention
|
|
952
953
|
* routing, a synthesized remote child, or a bare `engine.register` with no `origin` option), and
|
|
953
954
|
* for a workflow whose declaring package could not be resolved with confidence. A wrong origin is
|
|
954
955
|
* worse than an absent one: a filter that silently drops runs looks exactly like runs that never
|
|
955
|
-
* existed, so callers must
|
|
956
|
+
* existed, so callers must keep the no-origin bucket distinct and never fold it into a real package.
|
|
956
957
|
*/
|
|
957
958
|
origin?: string | undefined;
|
|
958
959
|
/**
|
|
@@ -1747,11 +1748,11 @@ interface RunQuery {
|
|
|
1747
1748
|
* Restrict to runs whose workflow was declared by this package (exact match against
|
|
1748
1749
|
* {@link WorkflowRun.origin}), ANDed with the other predicates.
|
|
1749
1750
|
*
|
|
1750
|
-
* A run with NO origin (
|
|
1751
|
+
* A run with NO origin (the console's `app` bucket — see the field) matches no `origin` VALUE at all, so a UI facet
|
|
1751
1752
|
* built on this must keep an "all origins" option: filtering by any single package silently hides
|
|
1752
1753
|
* every unattributed run, which reads to an operator as "those runs do not exist". `null` selects
|
|
1753
|
-
* exactly that absent bucket (`origin IS NULL`), so a paginated console can offer an
|
|
1754
|
-
* facet without having to hold every run in the browser to find them.
|
|
1754
|
+
* exactly that absent bucket (`origin IS NULL`), so a paginated console can offer an `app`
|
|
1755
|
+
* (no-origin) facet without having to hold every run in the browser to find them.
|
|
1755
1756
|
*/
|
|
1756
1757
|
origin?: string | null | undefined;
|
|
1757
1758
|
/**
|
|
@@ -5704,6 +5705,22 @@ declare class WorkflowEngine {
|
|
|
5704
5705
|
private markStarted;
|
|
5705
5706
|
private singletonWaitResult;
|
|
5706
5707
|
private execute;
|
|
5708
|
+
/**
|
|
5709
|
+
* Keep a wake that found `runId`'s lease held by a turn executing elsewhere, durably, so that turn
|
|
5710
|
+
* runs again once it ends instead of suspending on a snapshot that predates what the wake brought
|
|
5711
|
+
* (a signal, a child's completion). The request is a buffered signal on a token no workflow waits
|
|
5712
|
+
* on; the holder takes it after it releases the lease ({@link honorWakeRequests}).
|
|
5713
|
+
*
|
|
5714
|
+
* Written first and looked at second, against a holder that releases first and looks second:
|
|
5715
|
+
* whichever look runs last sees the other side's write. So when the run is no longer executing by
|
|
5716
|
+
* the time this re-reads it, the holder may have looked already, and this side takes the request
|
|
5717
|
+
* and wakes the run itself once the lease is free.
|
|
5718
|
+
*/
|
|
5719
|
+
private requestWakeAfterTurn;
|
|
5720
|
+
/** After a turn that suspended released its lease: run again if a wake was kept for it. */
|
|
5721
|
+
private honorWakeRequests;
|
|
5722
|
+
/** Take every wake request kept for `runId`; true when there was one. */
|
|
5723
|
+
private takeWakeRequests;
|
|
5707
5724
|
/**
|
|
5708
5725
|
* A wake that found the run leased by another instance is dropped, and normally that is fine: the
|
|
5709
5726
|
* 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
|