@dudousxd/nestjs-durable-core 0.75.1 → 0.76.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 +77 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +77 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -969,6 +969,16 @@ interface StateStore {
|
|
|
969
969
|
* being a single transaction; stores without transactions cannot give the strong guarantee.
|
|
970
970
|
*/
|
|
971
971
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
972
|
+
/**
|
|
973
|
+
* Overwrite the checkpoint at `(runId, seq)` with `checkpoint`, but only while the stored row is
|
|
974
|
+
* still `pending`; resolves whether it wrote. The engine writes a dispatched step's row from two
|
|
975
|
+
* places at once (a turn stamping its redispatch deadline, and the worker's result settling it),
|
|
976
|
+
* so a blind {@link saveCheckpoint} from a row read a moment earlier can put a `completed` step
|
|
977
|
+
* back to `pending`. This is the compare-and-set that prevents it.
|
|
978
|
+
*
|
|
979
|
+
* Optional: a store that omits it falls back to {@link saveCheckpoint}, which keeps that race.
|
|
980
|
+
*/
|
|
981
|
+
saveCheckpointIfPending?(checkpoint: StepCheckpoint): Promise<boolean>;
|
|
972
982
|
/** Used by recovery on boot to find runs to resume (crashed, left `running`). */
|
|
973
983
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
974
984
|
/** The oldest `pending` runs awaiting dispatch (FIFO, by `createdAt`), capped at `limit`. */
|
|
@@ -3790,6 +3800,12 @@ declare class WorkflowEngine {
|
|
|
3790
3800
|
private readonly updateValidators;
|
|
3791
3801
|
/** Runs being cancelled WITH saga compensation — see `cancel({ compensate: true })`. */
|
|
3792
3802
|
private readonly cancelRequested;
|
|
3803
|
+
/**
|
|
3804
|
+
* Seqs of the dispatched remote steps a turn suspended on, by run, while that turn executes on
|
|
3805
|
+
* THIS instance — so the turn can re-check them once its lease is released (see
|
|
3806
|
+
* {@link redriveSettledSteps}).
|
|
3807
|
+
*/
|
|
3808
|
+
private readonly awaitedRemoteSteps;
|
|
3793
3809
|
/** Flow-control admission backend for remote steps (see {@link registerQueue}). */
|
|
3794
3810
|
private readonly admission;
|
|
3795
3811
|
/** Runs on THIS instance blocked on admission, by queue — woken early on a freed-slot signal. */
|
|
@@ -4300,6 +4316,16 @@ declare class WorkflowEngine {
|
|
|
4300
4316
|
* itself. Only re-drives for a group with no waiter left whose checkpoints are all settled, which
|
|
4301
4317
|
* the next turn is then guaranteed to see — so it cannot loop.
|
|
4302
4318
|
*/
|
|
4319
|
+
/**
|
|
4320
|
+
* Re-drive a run that just suspended on dispatched remote steps which, by now, have a result.
|
|
4321
|
+
*
|
|
4322
|
+
* Same race as {@link redriveSettledChildren}, for `ctx.step`: a result landing while the turn
|
|
4323
|
+
* that dispatched it still holds the lease has its wake dropped by {@link execute}, and the turn
|
|
4324
|
+
* then suspends with nothing left to wake it before the step's redispatch deadline. Called after
|
|
4325
|
+
* the lease is released, so any later result wakes the run itself; it only re-drives for a
|
|
4326
|
+
* checkpoint that is already settled, which the next turn replays past — so it cannot loop.
|
|
4327
|
+
*/
|
|
4328
|
+
private redriveSettledSteps;
|
|
4303
4329
|
private redriveSettledChildren;
|
|
4304
4330
|
/**
|
|
4305
4331
|
* Deliver an external signal to the run waiting on `token`, resume it with `payload`, and return
|
|
@@ -4817,6 +4843,8 @@ declare class WorkflowEngine {
|
|
|
4817
4843
|
* capable+compatible worker has appeared, else re-parks with a fresh `wakeAt` (design §7.5). */
|
|
4818
4844
|
private dueBlockedRuns;
|
|
4819
4845
|
private callRemote;
|
|
4846
|
+
/** {@link StateStore.saveCheckpointIfPending}, or a plain save on a store without it. */
|
|
4847
|
+
private savePendingCheckpoint;
|
|
4820
4848
|
/** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
|
|
4821
4849
|
* dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
|
|
4822
4850
|
* {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
|
|
@@ -5492,6 +5520,9 @@ declare class CodecStateStore implements StateStore {
|
|
|
5492
5520
|
/** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
|
|
5493
5521
|
* engine's per-run fallback still kicks in through the wrapper. */
|
|
5494
5522
|
readonly deleteRuns?: (runIds: string[]) => Promise<void>;
|
|
5523
|
+
/** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
|
|
5524
|
+
* plain-save fallback still kicks in through the wrapper. */
|
|
5525
|
+
readonly saveCheckpointIfPending?: (checkpoint: StepCheckpoint) => Promise<boolean>;
|
|
5495
5526
|
/** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
|
|
5496
5527
|
* when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
|
|
5497
5528
|
readonly pruneTerminalRuns?: (policy: RetentionPolicy, nowMs: number, limit: number) => Promise<number>;
|
|
@@ -5961,6 +5992,7 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
5961
5992
|
pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
|
|
5962
5993
|
getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
|
|
5963
5994
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
5995
|
+
saveCheckpointIfPending(checkpoint: StepCheckpoint): Promise<boolean>;
|
|
5964
5996
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
5965
5997
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
5966
5998
|
listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -969,6 +969,16 @@ interface StateStore {
|
|
|
969
969
|
* being a single transaction; stores without transactions cannot give the strong guarantee.
|
|
970
970
|
*/
|
|
971
971
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
972
|
+
/**
|
|
973
|
+
* Overwrite the checkpoint at `(runId, seq)` with `checkpoint`, but only while the stored row is
|
|
974
|
+
* still `pending`; resolves whether it wrote. The engine writes a dispatched step's row from two
|
|
975
|
+
* places at once (a turn stamping its redispatch deadline, and the worker's result settling it),
|
|
976
|
+
* so a blind {@link saveCheckpoint} from a row read a moment earlier can put a `completed` step
|
|
977
|
+
* back to `pending`. This is the compare-and-set that prevents it.
|
|
978
|
+
*
|
|
979
|
+
* Optional: a store that omits it falls back to {@link saveCheckpoint}, which keeps that race.
|
|
980
|
+
*/
|
|
981
|
+
saveCheckpointIfPending?(checkpoint: StepCheckpoint): Promise<boolean>;
|
|
972
982
|
/** Used by recovery on boot to find runs to resume (crashed, left `running`). */
|
|
973
983
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
974
984
|
/** The oldest `pending` runs awaiting dispatch (FIFO, by `createdAt`), capped at `limit`. */
|
|
@@ -3790,6 +3800,12 @@ declare class WorkflowEngine {
|
|
|
3790
3800
|
private readonly updateValidators;
|
|
3791
3801
|
/** Runs being cancelled WITH saga compensation — see `cancel({ compensate: true })`. */
|
|
3792
3802
|
private readonly cancelRequested;
|
|
3803
|
+
/**
|
|
3804
|
+
* Seqs of the dispatched remote steps a turn suspended on, by run, while that turn executes on
|
|
3805
|
+
* THIS instance — so the turn can re-check them once its lease is released (see
|
|
3806
|
+
* {@link redriveSettledSteps}).
|
|
3807
|
+
*/
|
|
3808
|
+
private readonly awaitedRemoteSteps;
|
|
3793
3809
|
/** Flow-control admission backend for remote steps (see {@link registerQueue}). */
|
|
3794
3810
|
private readonly admission;
|
|
3795
3811
|
/** Runs on THIS instance blocked on admission, by queue — woken early on a freed-slot signal. */
|
|
@@ -4300,6 +4316,16 @@ declare class WorkflowEngine {
|
|
|
4300
4316
|
* itself. Only re-drives for a group with no waiter left whose checkpoints are all settled, which
|
|
4301
4317
|
* the next turn is then guaranteed to see — so it cannot loop.
|
|
4302
4318
|
*/
|
|
4319
|
+
/**
|
|
4320
|
+
* Re-drive a run that just suspended on dispatched remote steps which, by now, have a result.
|
|
4321
|
+
*
|
|
4322
|
+
* Same race as {@link redriveSettledChildren}, for `ctx.step`: a result landing while the turn
|
|
4323
|
+
* that dispatched it still holds the lease has its wake dropped by {@link execute}, and the turn
|
|
4324
|
+
* then suspends with nothing left to wake it before the step's redispatch deadline. Called after
|
|
4325
|
+
* the lease is released, so any later result wakes the run itself; it only re-drives for a
|
|
4326
|
+
* checkpoint that is already settled, which the next turn replays past — so it cannot loop.
|
|
4327
|
+
*/
|
|
4328
|
+
private redriveSettledSteps;
|
|
4303
4329
|
private redriveSettledChildren;
|
|
4304
4330
|
/**
|
|
4305
4331
|
* Deliver an external signal to the run waiting on `token`, resume it with `payload`, and return
|
|
@@ -4817,6 +4843,8 @@ declare class WorkflowEngine {
|
|
|
4817
4843
|
* capable+compatible worker has appeared, else re-parks with a fresh `wakeAt` (design §7.5). */
|
|
4818
4844
|
private dueBlockedRuns;
|
|
4819
4845
|
private callRemote;
|
|
4846
|
+
/** {@link StateStore.saveCheckpointIfPending}, or a plain save on a store without it. */
|
|
4847
|
+
private savePendingCheckpoint;
|
|
4820
4848
|
/** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
|
|
4821
4849
|
* dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
|
|
4822
4850
|
* {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
|
|
@@ -5492,6 +5520,9 @@ declare class CodecStateStore implements StateStore {
|
|
|
5492
5520
|
/** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
|
|
5493
5521
|
* engine's per-run fallback still kicks in through the wrapper. */
|
|
5494
5522
|
readonly deleteRuns?: (runIds: string[]) => Promise<void>;
|
|
5523
|
+
/** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
|
|
5524
|
+
* plain-save fallback still kicks in through the wrapper. */
|
|
5525
|
+
readonly saveCheckpointIfPending?: (checkpoint: StepCheckpoint) => Promise<boolean>;
|
|
5495
5526
|
/** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
|
|
5496
5527
|
* when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
|
|
5497
5528
|
readonly pruneTerminalRuns?: (policy: RetentionPolicy, nowMs: number, limit: number) => Promise<number>;
|
|
@@ -5961,6 +5992,7 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
5961
5992
|
pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
|
|
5962
5993
|
getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
|
|
5963
5994
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
5995
|
+
saveCheckpointIfPending(checkpoint: StepCheckpoint): Promise<boolean>;
|
|
5964
5996
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
5965
5997
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
5966
5998
|
listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]>;
|
package/dist/index.js
CHANGED
|
@@ -3698,6 +3698,12 @@ var WorkflowEngine = class {
|
|
|
3698
3698
|
updateValidators = /* @__PURE__ */ new Map();
|
|
3699
3699
|
/** Runs being cancelled WITH saga compensation — see `cancel({ compensate: true })`. */
|
|
3700
3700
|
cancelRequested = /* @__PURE__ */ new Set();
|
|
3701
|
+
/**
|
|
3702
|
+
* Seqs of the dispatched remote steps a turn suspended on, by run, while that turn executes on
|
|
3703
|
+
* THIS instance — so the turn can re-check them once its lease is released (see
|
|
3704
|
+
* {@link redriveSettledSteps}).
|
|
3705
|
+
*/
|
|
3706
|
+
awaitedRemoteSteps = /* @__PURE__ */ new Map();
|
|
3701
3707
|
/** Flow-control admission backend for remote steps (see {@link registerQueue}). */
|
|
3702
3708
|
admission;
|
|
3703
3709
|
/** Runs on THIS instance blocked on admission, by queue — woken early on a freed-slot signal. */
|
|
@@ -4172,7 +4178,18 @@ var WorkflowEngine = class {
|
|
|
4172
4178
|
createdAt: now,
|
|
4173
4179
|
updatedAt: now
|
|
4174
4180
|
};
|
|
4175
|
-
|
|
4181
|
+
try {
|
|
4182
|
+
await this.store.createRun(run);
|
|
4183
|
+
} catch (err) {
|
|
4184
|
+
const winner = await this.store.getRun(runId).catch(() => null);
|
|
4185
|
+
if (!winner) throw err;
|
|
4186
|
+
return {
|
|
4187
|
+
runId,
|
|
4188
|
+
status: winner.status,
|
|
4189
|
+
output: winner.output,
|
|
4190
|
+
error: winner.error
|
|
4191
|
+
};
|
|
4192
|
+
}
|
|
4176
4193
|
await this.runDispatcher.dispatch(runId);
|
|
4177
4194
|
if (this.controlPlane) {
|
|
4178
4195
|
void this.controlPlane.publishControl({
|
|
@@ -5101,6 +5118,24 @@ var WorkflowEngine = class {
|
|
|
5101
5118
|
* itself. Only re-drives for a group with no waiter left whose checkpoints are all settled, which
|
|
5102
5119
|
* the next turn is then guaranteed to see — so it cannot loop.
|
|
5103
5120
|
*/
|
|
5121
|
+
/**
|
|
5122
|
+
* Re-drive a run that just suspended on dispatched remote steps which, by now, have a result.
|
|
5123
|
+
*
|
|
5124
|
+
* Same race as {@link redriveSettledChildren}, for `ctx.step`: a result landing while the turn
|
|
5125
|
+
* that dispatched it still holds the lease has its wake dropped by {@link execute}, and the turn
|
|
5126
|
+
* then suspends with nothing left to wake it before the step's redispatch deadline. Called after
|
|
5127
|
+
* the lease is released, so any later result wakes the run itself; it only re-drives for a
|
|
5128
|
+
* checkpoint that is already settled, which the next turn replays past — so it cannot loop.
|
|
5129
|
+
*/
|
|
5130
|
+
async redriveSettledSteps(runId, seqs) {
|
|
5131
|
+
for (const seq of seqs) {
|
|
5132
|
+
const cp = await this.store.getCheckpoint(runId, seq);
|
|
5133
|
+
if (cp && (cp.status === "completed" || cp.status === "failed")) {
|
|
5134
|
+
await this.resumeImplicit(runId);
|
|
5135
|
+
return;
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
}
|
|
5104
5139
|
async redriveSettledChildren(runId, fan) {
|
|
5105
5140
|
if (!this.store.hasSignalWaiter) return;
|
|
5106
5141
|
for (const wait of fan.waits) {
|
|
@@ -6555,6 +6590,9 @@ var WorkflowEngine = class {
|
|
|
6555
6590
|
const replay = /* @__PURE__ */ new Map();
|
|
6556
6591
|
for (const cp of snapshot) replay.set(cp.seq, cp);
|
|
6557
6592
|
let suspendedOnFan;
|
|
6593
|
+
let suspendedOnSteps = false;
|
|
6594
|
+
const awaitedSteps = /* @__PURE__ */ new Set();
|
|
6595
|
+
this.awaitedRemoteSteps.set(run.id, awaitedSteps);
|
|
6558
6596
|
const ctx = createWorkflowCtx(this.ctxHostFor(replay, run.namespace), run.id, compensations, run.workflow, registered?.searchAttributesSchema);
|
|
6559
6597
|
try {
|
|
6560
6598
|
const output = await runInWorkflowCtx(ctx, () => fn(ctx, run.input));
|
|
@@ -6611,6 +6649,7 @@ var WorkflowEngine = class {
|
|
|
6611
6649
|
wakeAt: err.wakeAt
|
|
6612
6650
|
});
|
|
6613
6651
|
suspendedOnFan = err.fan;
|
|
6652
|
+
suspendedOnSteps = suspended.status === "suspended";
|
|
6614
6653
|
return suspended;
|
|
6615
6654
|
}
|
|
6616
6655
|
if (this.cancelRequested.has(run.id)) {
|
|
@@ -6630,10 +6669,16 @@ var WorkflowEngine = class {
|
|
|
6630
6669
|
error: error2
|
|
6631
6670
|
});
|
|
6632
6671
|
} finally {
|
|
6672
|
+
if (this.awaitedRemoteSteps.get(run.id) === awaitedSteps) {
|
|
6673
|
+
this.awaitedRemoteSteps.delete(run.id);
|
|
6674
|
+
}
|
|
6633
6675
|
await this.store.releaseRunLock(run.id);
|
|
6634
6676
|
if (suspendedOnFan) {
|
|
6635
6677
|
void this.redriveSettledChildren(run.id, suspendedOnFan).catch(() => void 0);
|
|
6636
6678
|
}
|
|
6679
|
+
if (suspendedOnSteps && awaitedSteps.size > 0) {
|
|
6680
|
+
void this.redriveSettledSteps(run.id, awaitedSteps).catch(() => void 0);
|
|
6681
|
+
}
|
|
6637
6682
|
}
|
|
6638
6683
|
}
|
|
6639
6684
|
/**
|
|
@@ -7053,13 +7098,16 @@ var WorkflowEngine = class {
|
|
|
7053
7098
|
if (this.pool.size === 0) throw new Error("remote steps require a Transport");
|
|
7054
7099
|
if (step.timeoutMs) return this.callRemoteInMemory(runId, seq, step, input, transport, group);
|
|
7055
7100
|
if (existing?.status === "pending") {
|
|
7101
|
+
this.awaitedRemoteSteps.get(runId)?.add(seq);
|
|
7056
7102
|
if (this.remoteRedispatchMs == null) throw new WorkflowSuspended();
|
|
7057
7103
|
if (existing.wakeAt == null) {
|
|
7058
7104
|
const wakeAt = this.clock() + this.remoteRedispatchMs;
|
|
7059
|
-
await this.
|
|
7105
|
+
if (!await this.savePendingCheckpoint({
|
|
7060
7106
|
...existing,
|
|
7061
7107
|
wakeAt
|
|
7062
|
-
})
|
|
7108
|
+
})) {
|
|
7109
|
+
return this.callRemote(runId, seq, step, input, queue, transport, void 0, admission, routing);
|
|
7110
|
+
}
|
|
7063
7111
|
throw new WorkflowSuspended(wakeAt);
|
|
7064
7112
|
}
|
|
7065
7113
|
if (this.clock() < existing.wakeAt) throw new WorkflowSuspended(existing.wakeAt);
|
|
@@ -7072,7 +7120,7 @@ var WorkflowEngine = class {
|
|
|
7072
7120
|
const reAttempt = existing.attempts + 1;
|
|
7073
7121
|
const nextDeadline = this.clock() + this.remoteRedispatchMs;
|
|
7074
7122
|
const reEnqueuedAt = /* @__PURE__ */ new Date();
|
|
7075
|
-
await this.
|
|
7123
|
+
const claimed = await this.savePendingCheckpoint({
|
|
7076
7124
|
...existing,
|
|
7077
7125
|
attempts: reAttempt,
|
|
7078
7126
|
wakeAt: nextDeadline,
|
|
@@ -7086,6 +7134,9 @@ var WorkflowEngine = class {
|
|
|
7086
7134
|
lostStepEvent(this.clock(), reAttempt, "redispatched")
|
|
7087
7135
|
]
|
|
7088
7136
|
});
|
|
7137
|
+
if (!claimed) {
|
|
7138
|
+
return this.callRemote(runId, seq, step, input, queue, transport, void 0, admission, routing);
|
|
7139
|
+
}
|
|
7089
7140
|
await this.dispatchRemoteTask({
|
|
7090
7141
|
runId,
|
|
7091
7142
|
seq,
|
|
@@ -7173,8 +7224,15 @@ var WorkflowEngine = class {
|
|
|
7173
7224
|
name: step.name,
|
|
7174
7225
|
kind: "remote"
|
|
7175
7226
|
});
|
|
7227
|
+
this.awaitedRemoteSteps.get(runId)?.add(seq);
|
|
7176
7228
|
throw new WorkflowSuspended();
|
|
7177
7229
|
}
|
|
7230
|
+
/** {@link StateStore.saveCheckpointIfPending}, or a plain save on a store without it. */
|
|
7231
|
+
async savePendingCheckpoint(checkpoint) {
|
|
7232
|
+
if (this.store.saveCheckpointIfPending) return this.store.saveCheckpointIfPending(checkpoint);
|
|
7233
|
+
await this.store.saveCheckpoint(checkpoint);
|
|
7234
|
+
return true;
|
|
7235
|
+
}
|
|
7178
7236
|
/** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
|
|
7179
7237
|
* dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
|
|
7180
7238
|
* {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
|
|
@@ -7205,7 +7263,7 @@ var WorkflowEngine = class {
|
|
|
7205
7263
|
if (run && (run.status === "cancelled" || run.status === "completed")) return;
|
|
7206
7264
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
7207
7265
|
const startedAt = result.startedAt ? new Date(result.startedAt) : cp.startedAt;
|
|
7208
|
-
await this.
|
|
7266
|
+
const claimed = await this.savePendingCheckpoint({
|
|
7209
7267
|
...cp,
|
|
7210
7268
|
status: result.status,
|
|
7211
7269
|
output: result.status === "completed" ? result.output : cp.output,
|
|
@@ -7214,6 +7272,7 @@ var WorkflowEngine = class {
|
|
|
7214
7272
|
startedAt,
|
|
7215
7273
|
finishedAt
|
|
7216
7274
|
});
|
|
7275
|
+
if (!claimed) return;
|
|
7217
7276
|
this.emit({
|
|
7218
7277
|
type: result.status === "completed" ? "step.completed" : "step.failed",
|
|
7219
7278
|
runId: result.runId,
|
|
@@ -7606,6 +7665,9 @@ var CodecStateStore = class {
|
|
|
7606
7665
|
/** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
|
|
7607
7666
|
* engine's per-run fallback still kicks in through the wrapper. */
|
|
7608
7667
|
deleteRuns;
|
|
7668
|
+
/** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
|
|
7669
|
+
* plain-save fallback still kicks in through the wrapper. */
|
|
7670
|
+
saveCheckpointIfPending;
|
|
7609
7671
|
/** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
|
|
7610
7672
|
* when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
|
|
7611
7673
|
pruneTerminalRuns;
|
|
@@ -7633,6 +7695,8 @@ var CodecStateStore = class {
|
|
|
7633
7695
|
if (inner.tryAdmitSingleton) this.tryAdmitSingleton = inner.tryAdmitSingleton.bind(inner);
|
|
7634
7696
|
const deleteRuns = inner.deleteRuns;
|
|
7635
7697
|
if (deleteRuns) this.deleteRuns = (ids) => deleteRuns.call(inner, ids);
|
|
7698
|
+
const saveIfPending = inner.saveCheckpointIfPending;
|
|
7699
|
+
if (saveIfPending) this.saveCheckpointIfPending = (cp) => saveIfPending.call(inner, this.encCp(cp));
|
|
7636
7700
|
const prune = inner.pruneTerminalRuns;
|
|
7637
7701
|
if (prune) this.pruneTerminalRuns = (policy, now, limit) => prune.call(inner, policy, now, limit);
|
|
7638
7702
|
const count = inner.countRuns;
|
|
@@ -8196,6 +8260,14 @@ var InMemoryStateStore = class {
|
|
|
8196
8260
|
...checkpoint
|
|
8197
8261
|
});
|
|
8198
8262
|
}
|
|
8263
|
+
async saveCheckpointIfPending(checkpoint) {
|
|
8264
|
+
const key = this.key(checkpoint.runId, checkpoint.seq);
|
|
8265
|
+
if (this.checkpoints.get(key)?.status !== "pending") return false;
|
|
8266
|
+
this.checkpoints.set(key, {
|
|
8267
|
+
...checkpoint
|
|
8268
|
+
});
|
|
8269
|
+
return true;
|
|
8270
|
+
}
|
|
8199
8271
|
async listIncompleteRuns(namespace) {
|
|
8200
8272
|
return [
|
|
8201
8273
|
...this.runs.values()
|