@dudousxd/nestjs-durable-core 0.61.0 → 0.62.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 +56 -13
- 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 +56 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2396,6 +2396,10 @@ __name(mergeTags, "mergeTags");
|
|
|
2396
2396
|
var BREAKPOINT = "breakpoint";
|
|
2397
2397
|
var isBreakpoint = /* @__PURE__ */ __name((cp) => cp.status === "pending" && cp.name.startsWith(BREAKPOINT), "isBreakpoint");
|
|
2398
2398
|
var versionKey = /* @__PURE__ */ __name((name, version) => `${name}@${version}`, "versionKey");
|
|
2399
|
+
function stepGroup(step, runNamespace) {
|
|
2400
|
+
return tenantGroup(sanitizeQueueToken(step.name), step.partition ?? runNamespace);
|
|
2401
|
+
}
|
|
2402
|
+
__name(stepGroup, "stepGroup");
|
|
2399
2403
|
function nextContinuationId(runId) {
|
|
2400
2404
|
const m = runId.match(/^(.*)~(\d+)$/);
|
|
2401
2405
|
return m ? `${m[1]}~${Number(m[2]) + 1}` : `${runId}~1`;
|
|
@@ -3896,7 +3900,8 @@ var WorkflowEngine = class {
|
|
|
3896
3900
|
async workerHealth(extra = []) {
|
|
3897
3901
|
const groups = /* @__PURE__ */ new Set([
|
|
3898
3902
|
...this.knownGroups(extra),
|
|
3899
|
-
...await this.pool.listWorkerGroups()
|
|
3903
|
+
...await this.pool.listWorkerGroups(),
|
|
3904
|
+
...await this.inflightStepGroups()
|
|
3900
3905
|
]);
|
|
3901
3906
|
const workflowTokens = /* @__PURE__ */ new Set();
|
|
3902
3907
|
for (const def of this.workflows.values()) {
|
|
@@ -3917,6 +3922,38 @@ var WorkflowEngine = class {
|
|
|
3917
3922
|
return out;
|
|
3918
3923
|
}
|
|
3919
3924
|
/**
|
|
3925
|
+
* The routing groups of every in-flight run's still-`pending` remote step — the queues where work is
|
|
3926
|
+
* dispatched and awaiting a worker. Folded into {@link workerHealth} so a step waiting on a group
|
|
3927
|
+
* that is NEITHER a registration NOR heartbeating (the exact shape of a run stuck on an offline
|
|
3928
|
+
* tenant pool) still reports its backlog: without this the health scan can't "see" that queue, and
|
|
3929
|
+
* the dashboard shows the run as running instead of no-worker. Only the BullMQ transport introspects
|
|
3930
|
+
* health, so on any other transport this is harmless (the groups just resolve to no `groupHealth`).
|
|
3931
|
+
*
|
|
3932
|
+
* Cost: one `listRuns` over the non-terminal runs plus a checkpoint read each — a diagnostic-path
|
|
3933
|
+
* scan, not a hot path. Scoped to `running`/`suspended`/`blocked` (a `pending` run has dispatched no
|
|
3934
|
+
* step yet) and deduped to distinct groups.
|
|
3935
|
+
*/
|
|
3936
|
+
async inflightStepGroups() {
|
|
3937
|
+
const inflight = await this.store.listRuns({
|
|
3938
|
+
statuses: [
|
|
3939
|
+
"running",
|
|
3940
|
+
"suspended",
|
|
3941
|
+
"blocked"
|
|
3942
|
+
]
|
|
3943
|
+
});
|
|
3944
|
+
const groups = /* @__PURE__ */ new Set();
|
|
3945
|
+
for (const run of inflight) {
|
|
3946
|
+
for (const cp of await this.store.listCheckpoints(run.id)) {
|
|
3947
|
+
if (cp.kind === "remote" && cp.status === "pending" && cp.workerGroup) {
|
|
3948
|
+
groups.add(cp.workerGroup);
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
return [
|
|
3953
|
+
...groups
|
|
3954
|
+
];
|
|
3955
|
+
}
|
|
3956
|
+
/**
|
|
3920
3957
|
* Persist a streamed local-step lifecycle event from a remote workflow worker (see
|
|
3921
3958
|
* {@link WorkflowStepEvent}). A Python `@workflow` runs its `ctx.step`s inline over one turn that
|
|
3922
3959
|
* can last minutes; the worker streams each step's start/finish so the engine checkpoints it LIVE —
|
|
@@ -4880,7 +4917,7 @@ var WorkflowEngine = class {
|
|
|
4880
4917
|
*/
|
|
4881
4918
|
async dispatchCompensationAttempt(run, seq, name, def, args, attempt, replay) {
|
|
4882
4919
|
if (this.pool.size === 0) throw new Error("remote steps require a Transport");
|
|
4883
|
-
const group =
|
|
4920
|
+
const group = stepGroup(def, run.namespace);
|
|
4884
4921
|
const enqueuedAt = /* @__PURE__ */ new Date();
|
|
4885
4922
|
const cp = stepCheckpoint({
|
|
4886
4923
|
runId: run.id,
|
|
@@ -4928,7 +4965,12 @@ var WorkflowEngine = class {
|
|
|
4928
4965
|
startStep: /* @__PURE__ */ __name((s) => this.startStep(s), "startStep"),
|
|
4929
4966
|
completeStep: /* @__PURE__ */ __name((s) => this.completeStep(s), "completeStep"),
|
|
4930
4967
|
failStep: /* @__PURE__ */ __name((s) => this.failStep(s), "failStep"),
|
|
4931
|
-
|
|
4968
|
+
// Route the dispatch by the RUN's tenant (same reason as `startChild` below): the executing
|
|
4969
|
+
// engine may be an operator driving every namespace, so the token must come from the run, not
|
|
4970
|
+
// from this engine. See {@link stepGroup}.
|
|
4971
|
+
callRemote: /* @__PURE__ */ __name((runId, seq, step, input, queue, transport, admission) => this.callRemote(runId, seq, step, input, queue, transport, replay, admission, {
|
|
4972
|
+
namespace: parentNamespace
|
|
4973
|
+
}), "callRemote"),
|
|
4932
4974
|
// Defer so a fast child can't reentrantly resume a still-running parent. Stamp the child with
|
|
4933
4975
|
// the PARENT run's namespace (not this engine's) so a child belongs to the tenant/partition of
|
|
4934
4976
|
// the run it was spawned from — even when an operator (namespace: undefined, drives every
|
|
@@ -5110,14 +5152,15 @@ var WorkflowEngine = class {
|
|
|
5110
5152
|
});
|
|
5111
5153
|
return blocked.filter((r) => (this.namespace === void 0 || r.namespace === void 0 || r.namespace === this.namespace) && r.wakeAt !== void 0 && r.wakeAt <= nowMs);
|
|
5112
5154
|
}
|
|
5113
|
-
async callRemote(runId, seq, step, input, queue, transport, replay, admission) {
|
|
5155
|
+
async callRemote(runId, seq, step, input, queue, transport, replay, admission, routing) {
|
|
5156
|
+
const group = stepGroup(step, routing?.namespace);
|
|
5114
5157
|
const existing = replay?.get(seq) ?? await this.store.getCheckpoint(runId, seq);
|
|
5115
5158
|
if (existing && existing.name !== step.name) {
|
|
5116
5159
|
throw new NonDeterminismError(runId, seq, step.name, existing.name);
|
|
5117
5160
|
}
|
|
5118
5161
|
if (existing?.status === "completed") return existing.output;
|
|
5119
5162
|
if (this.pool.size === 0) throw new Error("remote steps require a Transport");
|
|
5120
|
-
if (step.timeoutMs) return this.callRemoteInMemory(runId, seq, step, input, transport);
|
|
5163
|
+
if (step.timeoutMs) return this.callRemoteInMemory(runId, seq, step, input, transport, group);
|
|
5121
5164
|
if (existing?.status === "pending") {
|
|
5122
5165
|
if (this.remoteRedispatchMs == null) throw new WorkflowSuspended();
|
|
5123
5166
|
if (existing.wakeAt == null) {
|
|
@@ -5151,7 +5194,7 @@ var WorkflowEngine = class {
|
|
|
5151
5194
|
seq,
|
|
5152
5195
|
name: step.name,
|
|
5153
5196
|
stepId: existing.stepId ?? stepId(runId, seq),
|
|
5154
|
-
group: existing.workerGroup ??
|
|
5197
|
+
group: existing.workerGroup ?? group,
|
|
5155
5198
|
input: existing.input,
|
|
5156
5199
|
priority: admission?.priority,
|
|
5157
5200
|
attempt: reAttempt,
|
|
@@ -5175,7 +5218,7 @@ var WorkflowEngine = class {
|
|
|
5175
5218
|
if (this.clock() < existing.wakeAt) throw new WorkflowSuspended(existing.wakeAt);
|
|
5176
5219
|
attempt = existing.attempts + 1;
|
|
5177
5220
|
}
|
|
5178
|
-
await this.ensureRoutable(
|
|
5221
|
+
await this.ensureRoutable(group, step.requires);
|
|
5179
5222
|
const id = stepId(runId, seq);
|
|
5180
5223
|
if (queue && this.admission.handles(queue)) {
|
|
5181
5224
|
const decision = await this.admission.tryAdmit(queue, {
|
|
@@ -5202,7 +5245,7 @@ var WorkflowEngine = class {
|
|
|
5202
5245
|
status: "pending",
|
|
5203
5246
|
input,
|
|
5204
5247
|
attempts: attempt,
|
|
5205
|
-
workerGroup:
|
|
5248
|
+
workerGroup: group,
|
|
5206
5249
|
enqueuedAt,
|
|
5207
5250
|
startedAt: enqueuedAt,
|
|
5208
5251
|
finishedAt: enqueuedAt
|
|
@@ -5212,7 +5255,7 @@ var WorkflowEngine = class {
|
|
|
5212
5255
|
seq,
|
|
5213
5256
|
name: step.name,
|
|
5214
5257
|
stepId: id,
|
|
5215
|
-
group
|
|
5258
|
+
group,
|
|
5216
5259
|
input,
|
|
5217
5260
|
priority: admission?.priority,
|
|
5218
5261
|
attempt,
|
|
@@ -5360,9 +5403,9 @@ var WorkflowEngine = class {
|
|
|
5360
5403
|
await this.admission.release(queue, id);
|
|
5361
5404
|
}
|
|
5362
5405
|
/** In-memory await path for a remote step with a liveness `timeoutMs` (re-dispatch on timeout). */
|
|
5363
|
-
async callRemoteInMemory(runId, seq, step, input, transport) {
|
|
5406
|
+
async callRemoteInMemory(runId, seq, step, input, transport, group = stepGroup(step, void 0)) {
|
|
5364
5407
|
if (this.pool.size === 0) throw new Error("remote steps require a Transport");
|
|
5365
|
-
await this.ensureRoutable(
|
|
5408
|
+
await this.ensureRoutable(group, step.requires);
|
|
5366
5409
|
const validInput = step.input ? step.input.parse(input) : input;
|
|
5367
5410
|
const id = stepId(runId, seq);
|
|
5368
5411
|
const enqueuedAt = /* @__PURE__ */ new Date();
|
|
@@ -5386,7 +5429,7 @@ var WorkflowEngine = class {
|
|
|
5386
5429
|
seq,
|
|
5387
5430
|
name: step.name,
|
|
5388
5431
|
stepId: id,
|
|
5389
|
-
group
|
|
5432
|
+
group,
|
|
5390
5433
|
input: validInput,
|
|
5391
5434
|
traceparent: this.traceparent?.(),
|
|
5392
5435
|
context: this.context?.(),
|
|
@@ -5405,7 +5448,7 @@ var WorkflowEngine = class {
|
|
|
5405
5448
|
output,
|
|
5406
5449
|
events: resolution.events,
|
|
5407
5450
|
attempts: attempt,
|
|
5408
|
-
workerGroup:
|
|
5451
|
+
workerGroup: group,
|
|
5409
5452
|
enqueuedAt,
|
|
5410
5453
|
startedAt
|
|
5411
5454
|
});
|