@dudousxd/nestjs-durable-core 0.54.0 → 0.55.0
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 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +43 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2618,6 +2618,19 @@ declare class WorkflowEngine {
|
|
|
2618
2618
|
* knowing about the child feature.
|
|
2619
2619
|
*/
|
|
2620
2620
|
private notifyParent;
|
|
2621
|
+
/**
|
|
2622
|
+
* Deferred child start shared by the in-process ctx host and the remote `startChild` command.
|
|
2623
|
+
* Deferred (microtask) so a fast child can't reentrantly resume a still-suspending parent. A start
|
|
2624
|
+
* that THROWS (unregistered/unroutable workflow, input validation, singleton back-pressure, store
|
|
2625
|
+
* failure) must NOT be swallowed: the parent is already suspended on `child:<childId>` (the waiter
|
|
2626
|
+
* is put BEFORE start on every path), so a silent drop parks it in suspended-forever, invisibly
|
|
2627
|
+
* re-attempting on every recovery wake — a misconfigured remote child looks exactly like a healthy
|
|
2628
|
+
* long wait. Instead the failure is delivered to that waiter like a failed child (notifyParent):
|
|
2629
|
+
* the parent resumes and fails loudly with the cause. For a fire-and-forget `ctx.startChild`
|
|
2630
|
+
* (spawn — no waiter) the completion is buffered; a later join by the same id consumes it and
|
|
2631
|
+
* correctly observes the failed start.
|
|
2632
|
+
*/
|
|
2633
|
+
private startChildDeferred;
|
|
2621
2634
|
/**
|
|
2622
2635
|
* Cancel a run (e.g. from the dashboard). Returns null if the run does not exist. Pass
|
|
2623
2636
|
* `{ compensate: true }` to undo the saga first: the suspended run is resumed so its completed
|
package/dist/index.d.ts
CHANGED
|
@@ -2618,6 +2618,19 @@ declare class WorkflowEngine {
|
|
|
2618
2618
|
* knowing about the child feature.
|
|
2619
2619
|
*/
|
|
2620
2620
|
private notifyParent;
|
|
2621
|
+
/**
|
|
2622
|
+
* Deferred child start shared by the in-process ctx host and the remote `startChild` command.
|
|
2623
|
+
* Deferred (microtask) so a fast child can't reentrantly resume a still-suspending parent. A start
|
|
2624
|
+
* that THROWS (unregistered/unroutable workflow, input validation, singleton back-pressure, store
|
|
2625
|
+
* failure) must NOT be swallowed: the parent is already suspended on `child:<childId>` (the waiter
|
|
2626
|
+
* is put BEFORE start on every path), so a silent drop parks it in suspended-forever, invisibly
|
|
2627
|
+
* re-attempting on every recovery wake — a misconfigured remote child looks exactly like a healthy
|
|
2628
|
+
* long wait. Instead the failure is delivered to that waiter like a failed child (notifyParent):
|
|
2629
|
+
* the parent resumes and fails loudly with the cause. For a fire-and-forget `ctx.startChild`
|
|
2630
|
+
* (spawn — no waiter) the completion is buffered; a later join by the same id consumes it and
|
|
2631
|
+
* correctly observes the failed start.
|
|
2632
|
+
*/
|
|
2633
|
+
private startChildDeferred;
|
|
2621
2634
|
/**
|
|
2622
2635
|
* Cancel a run (e.g. from the dashboard). Returns null if the run does not exist. Pass
|
|
2623
2636
|
* `{ compensate: true }` to undo the saga first: the suspended run is resumed so its completed
|
package/dist/index.js
CHANGED
|
@@ -1099,6 +1099,21 @@ var TransportPool = class {
|
|
|
1099
1099
|
];
|
|
1100
1100
|
}
|
|
1101
1101
|
/**
|
|
1102
|
+
* The first transport (in pool order) reporting a LIVE heartbeat for `group` — the one a
|
|
1103
|
+
* convention-routed remote workflow must dispatch on. In a mixed pool (e.g. a tenant-scoped
|
|
1104
|
+
* control plane pairing its namespaced transport with a bare-prefix one for operator-convention
|
|
1105
|
+
* tenant workers), each transport sees a DIFFERENT keyspace: dispatching on `primary` while the
|
|
1106
|
+
* live worker heartbeats on another transport parks the task on a queue nobody consumes. Returns
|
|
1107
|
+
* `undefined` when no transport reports the group (mirrors the merged `listWorkerGroups` miss).
|
|
1108
|
+
*/
|
|
1109
|
+
async transportWithLiveGroup(group) {
|
|
1110
|
+
for (const { transport } of this.transports) {
|
|
1111
|
+
if (!transport.listWorkerGroups) continue;
|
|
1112
|
+
if ((await transport.listWorkerGroups()).includes(group)) return transport;
|
|
1113
|
+
}
|
|
1114
|
+
return void 0;
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1102
1117
|
* Propagate the engine's `namespace` to every transport that partitions by it — so the same
|
|
1103
1118
|
* namespace that scopes the store also scopes each transport's queues/keys. A transport that
|
|
1104
1119
|
* doesn't partition (no `useNamespace`) is skipped. Idempotent; a transport given an explicit
|
|
@@ -2414,10 +2429,10 @@ var WorkflowEngine = class {
|
|
|
2414
2429
|
* liveness changes between calls, exactly as {@link synthesizeRemoteChild} does.
|
|
2415
2430
|
*/
|
|
2416
2431
|
async resolveRemoteByConvention(run) {
|
|
2417
|
-
const liveGroups = await this.pool.listWorkerGroups();
|
|
2418
2432
|
const group = tenantGroup(sanitizeQueueToken(run.workflow), run.namespace);
|
|
2419
|
-
|
|
2420
|
-
|
|
2433
|
+
const liveTransport = await this.pool.transportWithLiveGroup(group);
|
|
2434
|
+
if (!liveTransport) return void 0;
|
|
2435
|
+
const executor = new RemoteWorkflowExecutor(liveTransport, run.workflow, run.namespace);
|
|
2421
2436
|
return {
|
|
2422
2437
|
name: run.workflow,
|
|
2423
2438
|
version: run.workflowVersion,
|
|
@@ -3036,6 +3051,27 @@ var WorkflowEngine = class {
|
|
|
3036
3051
|
void this.signal(`child:${runId}`, completion).catch(() => void 0);
|
|
3037
3052
|
}
|
|
3038
3053
|
/**
|
|
3054
|
+
* Deferred child start shared by the in-process ctx host and the remote `startChild` command.
|
|
3055
|
+
* Deferred (microtask) so a fast child can't reentrantly resume a still-suspending parent. A start
|
|
3056
|
+
* that THROWS (unregistered/unroutable workflow, input validation, singleton back-pressure, store
|
|
3057
|
+
* failure) must NOT be swallowed: the parent is already suspended on `child:<childId>` (the waiter
|
|
3058
|
+
* is put BEFORE start on every path), so a silent drop parks it in suspended-forever, invisibly
|
|
3059
|
+
* re-attempting on every recovery wake — a misconfigured remote child looks exactly like a healthy
|
|
3060
|
+
* long wait. Instead the failure is delivered to that waiter like a failed child (notifyParent):
|
|
3061
|
+
* the parent resumes and fails loudly with the cause. For a fire-and-forget `ctx.startChild`
|
|
3062
|
+
* (spawn — no waiter) the completion is buffered; a later join by the same id consumes it and
|
|
3063
|
+
* correctly observes the failed start.
|
|
3064
|
+
*/
|
|
3065
|
+
startChildDeferred(workflow, input, childId, opts) {
|
|
3066
|
+
queueMicrotask(() => void this.start(workflow, input, childId, opts).catch((err) => {
|
|
3067
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3068
|
+
this.notifyParent(childId, {
|
|
3069
|
+
ok: false,
|
|
3070
|
+
error: `child workflow "${workflow}" failed to start: ${message}`
|
|
3071
|
+
});
|
|
3072
|
+
}));
|
|
3073
|
+
}
|
|
3074
|
+
/**
|
|
3039
3075
|
* Cancel a run (e.g. from the dashboard). Returns null if the run does not exist. Pass
|
|
3040
3076
|
* `{ compensate: true }` to undo the saga first: the suspended run is resumed so its completed
|
|
3041
3077
|
* steps' compensations run in reverse (visible as `compensate:<step>` events), then it's marked
|
|
@@ -3859,9 +3895,9 @@ var WorkflowEngine = class {
|
|
|
3859
3895
|
parallelGroup: cmd.parallelGroup
|
|
3860
3896
|
});
|
|
3861
3897
|
if (!await this.store.getRun(childId)) {
|
|
3862
|
-
|
|
3898
|
+
this.startChildDeferred(cmd.workflow, cmd.input, childId, {
|
|
3863
3899
|
namespace: run.namespace
|
|
3864
|
-
})
|
|
3900
|
+
});
|
|
3865
3901
|
}
|
|
3866
3902
|
} else {
|
|
3867
3903
|
throw new Error(`remote workflow command '${cmd.kind}' is not supported yet`);
|
|
@@ -4240,10 +4276,10 @@ var WorkflowEngine = class {
|
|
|
4240
4276
|
// `davi-local` pipeline would stamp its `processing` child `default` and it would leak off the
|
|
4241
4277
|
// tenant's worker pool onto the shared/dev workers.
|
|
4242
4278
|
startChild: /* @__PURE__ */ __name((workflow, input, id, priority) => {
|
|
4243
|
-
|
|
4279
|
+
this.startChildDeferred(workflow, input, id, {
|
|
4244
4280
|
priority,
|
|
4245
4281
|
namespace: parentNamespace
|
|
4246
|
-
})
|
|
4282
|
+
});
|
|
4247
4283
|
}, "startChild"),
|
|
4248
4284
|
// Deferred for the same reentrancy reason as `startChild` above. `cancel()` is already
|
|
4249
4285
|
// idempotent on a terminal/cancelled run (returns its existing status without side effects), so
|