@dudousxd/nestjs-durable-core 0.75.2 → 0.76.1
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 +67 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +67 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3867,6 +3867,12 @@ var WorkflowEngine = class {
|
|
|
3867
3867
|
* {@link redriveSettledSteps}).
|
|
3868
3868
|
*/
|
|
3869
3869
|
awaitedRemoteSteps = /* @__PURE__ */ new Map();
|
|
3870
|
+
/**
|
|
3871
|
+
* When THIS instance settled a remote step from its result, by `runId:seq`. That result's resume
|
|
3872
|
+
* runs here, and `execute` lets it into a lease this instance holds, so its wake is never the
|
|
3873
|
+
* dropped one {@link redriveSettledSteps} recovers. Pruned by age (see {@link noteSettledHere}).
|
|
3874
|
+
*/
|
|
3875
|
+
settledHere = /* @__PURE__ */ new Map();
|
|
3870
3876
|
/** Flow-control admission backend for remote steps (see {@link registerQueue}). */
|
|
3871
3877
|
admission;
|
|
3872
3878
|
/** Runs on THIS instance blocked on admission, by queue — woken early on a freed-slot signal. */
|
|
@@ -4341,7 +4347,18 @@ var WorkflowEngine = class {
|
|
|
4341
4347
|
createdAt: now,
|
|
4342
4348
|
updatedAt: now
|
|
4343
4349
|
};
|
|
4344
|
-
|
|
4350
|
+
try {
|
|
4351
|
+
await this.store.createRun(run);
|
|
4352
|
+
} catch (err) {
|
|
4353
|
+
const winner = await this.store.getRun(runId).catch(() => null);
|
|
4354
|
+
if (!winner) throw err;
|
|
4355
|
+
return {
|
|
4356
|
+
runId,
|
|
4357
|
+
status: winner.status,
|
|
4358
|
+
output: winner.output,
|
|
4359
|
+
error: winner.error
|
|
4360
|
+
};
|
|
4361
|
+
}
|
|
4345
4362
|
await this.runDispatcher.dispatch(runId);
|
|
4346
4363
|
if (this.controlPlane) {
|
|
4347
4364
|
void this.controlPlane.publishControl({
|
|
@@ -5283,6 +5300,16 @@ var WorkflowEngine = class {
|
|
|
5283
5300
|
for (const seq of seqs) {
|
|
5284
5301
|
const cp = await this.store.getCheckpoint(runId, seq);
|
|
5285
5302
|
if (cp && (cp.status === "completed" || cp.status === "failed")) {
|
|
5303
|
+
if (this.settledHere.has(`${runId}:${seq}`)) return;
|
|
5304
|
+
const nowMs = this.clock();
|
|
5305
|
+
if (!await this.store.tryLockRun(runId, this.instanceId, nowMs + this.leaseMs, nowMs)) {
|
|
5306
|
+
return;
|
|
5307
|
+
}
|
|
5308
|
+
const run = await this.store.getRun(runId);
|
|
5309
|
+
if (run?.status !== "suspended") {
|
|
5310
|
+
await this.store.releaseRunLock(runId);
|
|
5311
|
+
return;
|
|
5312
|
+
}
|
|
5286
5313
|
await this.resumeImplicit(runId);
|
|
5287
5314
|
return;
|
|
5288
5315
|
}
|
|
@@ -7254,10 +7281,12 @@ var WorkflowEngine = class {
|
|
|
7254
7281
|
if (this.remoteRedispatchMs == null) throw new WorkflowSuspended();
|
|
7255
7282
|
if (existing.wakeAt == null) {
|
|
7256
7283
|
const wakeAt = this.clock() + this.remoteRedispatchMs;
|
|
7257
|
-
await this.
|
|
7284
|
+
if (!await this.savePendingCheckpoint({
|
|
7258
7285
|
...existing,
|
|
7259
7286
|
wakeAt
|
|
7260
|
-
})
|
|
7287
|
+
})) {
|
|
7288
|
+
return this.callRemote(runId, seq, step, input, queue, transport, void 0, admission, routing);
|
|
7289
|
+
}
|
|
7261
7290
|
throw new WorkflowSuspended(wakeAt);
|
|
7262
7291
|
}
|
|
7263
7292
|
if (this.clock() < existing.wakeAt) throw new WorkflowSuspended(existing.wakeAt);
|
|
@@ -7270,7 +7299,7 @@ var WorkflowEngine = class {
|
|
|
7270
7299
|
const reAttempt = existing.attempts + 1;
|
|
7271
7300
|
const nextDeadline = this.clock() + this.remoteRedispatchMs;
|
|
7272
7301
|
const reEnqueuedAt = /* @__PURE__ */ new Date();
|
|
7273
|
-
await this.
|
|
7302
|
+
const claimed = await this.savePendingCheckpoint({
|
|
7274
7303
|
...existing,
|
|
7275
7304
|
attempts: reAttempt,
|
|
7276
7305
|
wakeAt: nextDeadline,
|
|
@@ -7284,6 +7313,9 @@ var WorkflowEngine = class {
|
|
|
7284
7313
|
lostStepEvent(this.clock(), reAttempt, "redispatched")
|
|
7285
7314
|
]
|
|
7286
7315
|
});
|
|
7316
|
+
if (!claimed) {
|
|
7317
|
+
return this.callRemote(runId, seq, step, input, queue, transport, void 0, admission, routing);
|
|
7318
|
+
}
|
|
7287
7319
|
await this.dispatchRemoteTask({
|
|
7288
7320
|
runId,
|
|
7289
7321
|
seq,
|
|
@@ -7374,6 +7406,21 @@ var WorkflowEngine = class {
|
|
|
7374
7406
|
this.awaitedRemoteSteps.get(runId)?.add(seq);
|
|
7375
7407
|
throw new WorkflowSuspended();
|
|
7376
7408
|
}
|
|
7409
|
+
/** Remember a step settled here, forgetting entries older than a lease so the map stays small. */
|
|
7410
|
+
noteSettledHere(key) {
|
|
7411
|
+
const now = this.clock();
|
|
7412
|
+
this.settledHere.set(key, now);
|
|
7413
|
+
if (this.settledHere.size < 1024) return;
|
|
7414
|
+
for (const [k, at] of this.settledHere) {
|
|
7415
|
+
if (now - at > this.leaseMs) this.settledHere.delete(k);
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7418
|
+
/** {@link StateStore.saveCheckpointIfPending}, or a plain save on a store without it. */
|
|
7419
|
+
async savePendingCheckpoint(checkpoint) {
|
|
7420
|
+
if (this.store.saveCheckpointIfPending) return this.store.saveCheckpointIfPending(checkpoint);
|
|
7421
|
+
await this.store.saveCheckpoint(checkpoint);
|
|
7422
|
+
return true;
|
|
7423
|
+
}
|
|
7377
7424
|
/** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
|
|
7378
7425
|
* dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
|
|
7379
7426
|
* {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
|
|
@@ -7404,7 +7451,7 @@ var WorkflowEngine = class {
|
|
|
7404
7451
|
if (run && (run.status === "cancelled" || run.status === "completed")) return;
|
|
7405
7452
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
7406
7453
|
const startedAt = result.startedAt ? new Date(result.startedAt) : cp.startedAt;
|
|
7407
|
-
await this.
|
|
7454
|
+
const claimed = await this.savePendingCheckpoint({
|
|
7408
7455
|
...cp,
|
|
7409
7456
|
status: result.status,
|
|
7410
7457
|
output: result.status === "completed" ? result.output : cp.output,
|
|
@@ -7413,6 +7460,8 @@ var WorkflowEngine = class {
|
|
|
7413
7460
|
startedAt,
|
|
7414
7461
|
finishedAt
|
|
7415
7462
|
});
|
|
7463
|
+
if (!claimed) return;
|
|
7464
|
+
this.noteSettledHere(`${result.runId}:${result.seq}`);
|
|
7416
7465
|
this.emit({
|
|
7417
7466
|
type: result.status === "completed" ? "step.completed" : "step.failed",
|
|
7418
7467
|
runId: result.runId,
|
|
@@ -7805,6 +7854,9 @@ var CodecStateStore = class {
|
|
|
7805
7854
|
/** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
|
|
7806
7855
|
* engine's per-run fallback still kicks in through the wrapper. */
|
|
7807
7856
|
deleteRuns;
|
|
7857
|
+
/** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
|
|
7858
|
+
* plain-save fallback still kicks in through the wrapper. */
|
|
7859
|
+
saveCheckpointIfPending;
|
|
7808
7860
|
/** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
|
|
7809
7861
|
* when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
|
|
7810
7862
|
pruneTerminalRuns;
|
|
@@ -7832,6 +7884,8 @@ var CodecStateStore = class {
|
|
|
7832
7884
|
if (inner.tryAdmitSingleton) this.tryAdmitSingleton = inner.tryAdmitSingleton.bind(inner);
|
|
7833
7885
|
const deleteRuns = inner.deleteRuns;
|
|
7834
7886
|
if (deleteRuns) this.deleteRuns = (ids) => deleteRuns.call(inner, ids);
|
|
7887
|
+
const saveIfPending = inner.saveCheckpointIfPending;
|
|
7888
|
+
if (saveIfPending) this.saveCheckpointIfPending = (cp) => saveIfPending.call(inner, this.encCp(cp));
|
|
7835
7889
|
const prune = inner.pruneTerminalRuns;
|
|
7836
7890
|
if (prune) this.pruneTerminalRuns = (policy, now, limit) => prune.call(inner, policy, now, limit);
|
|
7837
7891
|
const count = inner.countRuns;
|
|
@@ -8395,6 +8449,14 @@ var InMemoryStateStore = class {
|
|
|
8395
8449
|
...checkpoint
|
|
8396
8450
|
});
|
|
8397
8451
|
}
|
|
8452
|
+
async saveCheckpointIfPending(checkpoint) {
|
|
8453
|
+
const key = this.key(checkpoint.runId, checkpoint.seq);
|
|
8454
|
+
if (this.checkpoints.get(key)?.status !== "pending") return false;
|
|
8455
|
+
this.checkpoints.set(key, {
|
|
8456
|
+
...checkpoint
|
|
8457
|
+
});
|
|
8458
|
+
return true;
|
|
8459
|
+
}
|
|
8398
8460
|
async listIncompleteRuns(namespace) {
|
|
8399
8461
|
return [
|
|
8400
8462
|
...this.runs.values()
|