@dudousxd/nestjs-durable-core 0.80.1 → 0.82.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 +683 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +357 -21
- package/dist/index.d.ts +357 -21
- package/dist/index.js +672 -123
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1150,6 +1150,16 @@ interface StepError {
|
|
|
1150
1150
|
retryable?: boolean | undefined;
|
|
1151
1151
|
stack?: string | undefined;
|
|
1152
1152
|
}
|
|
1153
|
+
/**
|
|
1154
|
+
* See {@link StateStore.listOrphanedRuns}: the live leases a rebooted engine instance may take back
|
|
1155
|
+
* immediately, i.e. those its previous incarnation (same `instanceId`) held when it died.
|
|
1156
|
+
*/
|
|
1157
|
+
interface OwnedLeaseReclaim {
|
|
1158
|
+
/** The engine instance id the lease must be held by. */
|
|
1159
|
+
owner: string;
|
|
1160
|
+
/** Only leases expiring strictly before this epoch ms (the caller's boot time + `leaseMs`). */
|
|
1161
|
+
lockedBefore: number;
|
|
1162
|
+
}
|
|
1153
1163
|
interface StateStore {
|
|
1154
1164
|
/**
|
|
1155
1165
|
* Provision the tables/collections this store needs, idempotently. Called on boot when the
|
|
@@ -1251,8 +1261,16 @@ interface StateStore {
|
|
|
1251
1261
|
* Optional but recommended: without it the engine lists every incomplete run and filters the
|
|
1252
1262
|
* leases in process, which on a busy fleet reads every healthy running run once per tick per
|
|
1253
1263
|
* worker.
|
|
1254
|
-
|
|
1255
|
-
|
|
1264
|
+
*
|
|
1265
|
+
* When `ownedBy` is given, ALSO return the runs whose lease is still live but held by
|
|
1266
|
+
* `ownedBy.owner` with `lockedUntil < ownedBy.lockedBefore` (strictly), under the same status,
|
|
1267
|
+
* namespace, order and `limit`. The engine passes its own `instanceId` and its boot time plus
|
|
1268
|
+
* `leaseMs`: a lease that expires before then was taken by a PREVIOUS process with the same stable
|
|
1269
|
+
* `instanceId` (one killed without a graceful shutdown), never by this one, so it reclaims those
|
|
1270
|
+
* at once instead of waiting out the lease. A store that ignores the argument keeps the plain
|
|
1271
|
+
* behaviour: those runs are reclaimed once their lease expires.
|
|
1272
|
+
*/
|
|
1273
|
+
listOrphanedRuns?(nowMs: number, limit: number, namespace?: string, ownedBy?: OwnedLeaseReclaim): Promise<WorkflowRun[]>;
|
|
1256
1274
|
/** The oldest `pending` runs awaiting dispatch (FIFO, by `createdAt`), capped at `limit`. */
|
|
1257
1275
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
1258
1276
|
/**
|
|
@@ -1267,8 +1285,15 @@ interface StateStore {
|
|
|
1267
1285
|
* acquired — so concurrent engine instances never recover the same run twice.
|
|
1268
1286
|
*/
|
|
1269
1287
|
tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
|
|
1270
|
-
/**
|
|
1271
|
-
|
|
1288
|
+
/**
|
|
1289
|
+
* Release a run's recovery lease so another instance can pick it up (e.g. once it suspends).
|
|
1290
|
+
*
|
|
1291
|
+
* `owner`, when given, makes the release owner-scoped: clear the lease ONLY if `owner` still holds
|
|
1292
|
+
* it, so an instance releasing a lease it may have lost (a drain that timed out) never frees the
|
|
1293
|
+
* lease another instance took over. Without it the release is unconditional. A store that ignores
|
|
1294
|
+
* the argument stays correct, only less precise in that race.
|
|
1295
|
+
*/
|
|
1296
|
+
releaseRunLock(runId: string, owner?: string): Promise<void>;
|
|
1272
1297
|
/**
|
|
1273
1298
|
* Extend a run's lease to `leaseUntilMs`, but ONLY if `owner` still holds it — so a live worker
|
|
1274
1299
|
* heartbeating its long run keeps the lease, while a dead worker's lease still expires and gets
|
|
@@ -1568,6 +1593,13 @@ interface ScheduleQuery {
|
|
|
1568
1593
|
/** The terminal run statuses — a run in one of these is finished and will never change on its own.
|
|
1569
1594
|
* Only these are eligible for retention pruning (a {@link RetentionPolicy} targeting a non-terminal
|
|
1570
1595
|
* status would race the engine and delete live work). */
|
|
1596
|
+
/**
|
|
1597
|
+
* Normalise a namespace to the worker pool it names: `''` is the default pool, exactly like
|
|
1598
|
+
* `'default'` (the transport already maps both to the bare token), so it is stamped, polled and
|
|
1599
|
+
* compared as `'default'`. `undefined` passes through untouched: an UNSET engine namespace is the
|
|
1600
|
+
* operator (drives every namespace), and an unset run namespace belongs to everyone.
|
|
1601
|
+
*/
|
|
1602
|
+
declare function poolNamespace(namespace: string | undefined): string | undefined;
|
|
1571
1603
|
declare const TERMINAL_RUN_STATUSES: readonly RunStatus[];
|
|
1572
1604
|
/**
|
|
1573
1605
|
* One retention rule for hard-pruning terminal run history. Within `statuses` (terminal only), a run
|
|
@@ -3218,6 +3250,20 @@ interface EntityHost {
|
|
|
3218
3250
|
getEvent<T>(runId: string, key: string): Promise<T | undefined>;
|
|
3219
3251
|
signal(token: string, payload: unknown): Promise<unknown>;
|
|
3220
3252
|
}
|
|
3253
|
+
/**
|
|
3254
|
+
* What a workflow-side send needs on top of {@link EntityHost}: a durable buffer write it can AWAIT
|
|
3255
|
+
* inside its turn, and a way to wake an entity run that is parked on its wait. Optional so a bare
|
|
3256
|
+
* {@link EntityHost} (tests, older hosts) still works through {@link Entities.dispatch}.
|
|
3257
|
+
*/
|
|
3258
|
+
interface EntityWorkflowHost {
|
|
3259
|
+
/** Durably buffer `payload` on `token` (the store's `bufferSignal`). */
|
|
3260
|
+
bufferSignal(token: string, payload: unknown): Promise<void>;
|
|
3261
|
+
/** If a run is parked on `token`, wake it with `payload`; if none is, do nothing (no buffering). */
|
|
3262
|
+
wakeWaiter(token: string, payload: unknown): Promise<unknown>;
|
|
3263
|
+
/** Start `runId` of `workflow` if it doesn't exist yet (idempotent by run id). */
|
|
3264
|
+
ensureStarted(workflow: string, input: unknown, runId: string): Promise<unknown>;
|
|
3265
|
+
}
|
|
3266
|
+
declare const ENTITY_WORKFLOW = "__entity";
|
|
3221
3267
|
/**
|
|
3222
3268
|
* Durable keyed **entities** (virtual objects): a keyed actor whose handlers run **serialized per
|
|
3223
3269
|
* key** over **durable state**, exactly once. Each key is one long-lived run (`entity:<name>:<key>`)
|
|
@@ -3226,14 +3272,35 @@ interface EntityHost {
|
|
|
3226
3272
|
*/
|
|
3227
3273
|
declare class Entities {
|
|
3228
3274
|
private readonly host;
|
|
3275
|
+
private readonly workflowHost?;
|
|
3229
3276
|
private readonly configs;
|
|
3230
|
-
constructor(host: EntityHost);
|
|
3277
|
+
constructor(host: EntityHost, workflowHost?: EntityWorkflowHost | undefined);
|
|
3231
3278
|
register<S>(name: string, config: EntityConfig<S>): void;
|
|
3232
3279
|
/** Deliver an op to an entity's runner, starting it on first contact. `reply` (a signal token)
|
|
3233
3280
|
* receives the handler's result, for `ctx.callEntity`. */
|
|
3234
3281
|
dispatch(name: string, key: string, op: string, arg: unknown, reply?: string): Promise<{
|
|
3235
3282
|
runId: string;
|
|
3236
3283
|
}>;
|
|
3284
|
+
/**
|
|
3285
|
+
* The durable half of a send from INSIDE a workflow (`ctx.callEntity` / `ctx.signalEntity`): write
|
|
3286
|
+
* the op to the entity's signal buffer and return once it is stored, so the caller can checkpoint
|
|
3287
|
+
* after it. The op carries `id`, the caller's stable `<runId>:<seq>`, so if the caller dies between
|
|
3288
|
+
* this write and its checkpoint and sends again on replay, the entity skips the second copy. The
|
|
3289
|
+
* entity's run is also ensured here, awaited (`start` only enqueues, it never runs the body
|
|
3290
|
+
* inline), so an op sent on first contact can't be stranded in a buffer no run will ever read if
|
|
3291
|
+
* the process dies right after. The wake-up ({@link kick}) is separate and may be lost: a busy
|
|
3292
|
+
* entity reads the buffer at its next wait, and a parked one is paired with it by the engine's
|
|
3293
|
+
* `reconcileMs` sweep. Returns `false` on a host without a workflow host.
|
|
3294
|
+
*/
|
|
3295
|
+
enqueue(name: string, key: string, op: string, arg: unknown, id: string, reply?: string): Promise<boolean>;
|
|
3296
|
+
/**
|
|
3297
|
+
* Make the entity act on what {@link enqueue} buffered: wake its run if it is parked on its wait
|
|
3298
|
+
* (the run itself was ensured by `enqueue`; ensured again here, idempotently, for a caller replay
|
|
3299
|
+
* that only re-kicks). A run that is busy needs nothing: its next wait reads the buffer before
|
|
3300
|
+
* suspending. The wake carries a no-op `nudge`, never the op itself, so the op stays in
|
|
3301
|
+
* the buffer in arrival order and a lost or repeated kick costs at most one empty iteration.
|
|
3302
|
+
*/
|
|
3303
|
+
kick(name: string, key: string): Promise<void>;
|
|
3237
3304
|
signal(name: string, key: string, op: string, arg?: unknown): Promise<void>;
|
|
3238
3305
|
getState<S = unknown>(name: string, key: string): Promise<S | undefined>;
|
|
3239
3306
|
/** The built-in runner: one long-lived run per key, processing ops serially over state. */
|
|
@@ -3943,6 +4010,60 @@ declare class ScheduleClient {
|
|
|
3943
4010
|
private write;
|
|
3944
4011
|
}
|
|
3945
4012
|
|
|
4013
|
+
/** Default idle threshold for a stranded run: 15 minutes. */
|
|
4014
|
+
declare const DEFAULT_STALLED_AFTER_MS: number;
|
|
4015
|
+
/** The oldest unresolved remote step of a run — the lost-dispatch signature when it is old. */
|
|
4016
|
+
interface StalePendingStep {
|
|
4017
|
+
seq: number;
|
|
4018
|
+
name: string;
|
|
4019
|
+
/** How many times this step has been (re-)dispatched. A lost dispatch typically sits at 1. */
|
|
4020
|
+
attempts: number;
|
|
4021
|
+
/** Milliseconds since the step was enqueued to the transport. */
|
|
4022
|
+
ageMs: number;
|
|
4023
|
+
/**
|
|
4024
|
+
* The step's lease (`wakeAt`, epoch ms) when it has one: a step with a `timeoutMs`, a heartbeat
|
|
4025
|
+
* renewing it, or `remoteRedispatchMs`. `null` when nothing is leasing the step.
|
|
4026
|
+
*/
|
|
4027
|
+
leaseUntil: number | null;
|
|
4028
|
+
}
|
|
4029
|
+
/** What an `engine.onStalled` listener (and {@link findStalledRuns}) receives: a stranded run and why. */
|
|
4030
|
+
interface StalledRunInfo {
|
|
4031
|
+
run: WorkflowRun;
|
|
4032
|
+
/** Milliseconds since the run's last activity (`updatedAt`). */
|
|
4033
|
+
ageMs: number;
|
|
4034
|
+
/** Suspended with NO wake timer — nothing will re-drive it (the `reconcileMs: 0` hazard). */
|
|
4035
|
+
wakeForever: boolean;
|
|
4036
|
+
/** The oldest pending remote step with no live lease, when that is the stranding signature. */
|
|
4037
|
+
stalePending: StalePendingStep | null;
|
|
4038
|
+
}
|
|
4039
|
+
/** Options for {@link findStalledRuns}. */
|
|
4040
|
+
interface FindStalledRunsOptions {
|
|
4041
|
+
/** Idle threshold in ms. Default {@link DEFAULT_STALLED_AFTER_MS}. */
|
|
4042
|
+
thresholdMs?: number | undefined;
|
|
4043
|
+
/** Max candidate runs inspected (newest first). Default 1000. */
|
|
4044
|
+
scan?: number | undefined;
|
|
4045
|
+
/** Evaluate as of this time (epoch ms). Default `Date.now()`. */
|
|
4046
|
+
now?: number | undefined;
|
|
4047
|
+
/** Only runs in this namespace. Omit for every namespace. */
|
|
4048
|
+
namespace?: string | undefined;
|
|
4049
|
+
}
|
|
4050
|
+
/**
|
|
4051
|
+
* The stranded runs in a store right now — the query behind `engine.sweepStalled`/`onStalled`,
|
|
4052
|
+
* `engine.listStalledRuns` and the CLI's `durable inspect --stale`. Works on a bare store, so an
|
|
4053
|
+
* ops script or a CLI can run it without an engine.
|
|
4054
|
+
*
|
|
4055
|
+
* A `running`/`suspended` run qualifies when it has been untouched for `thresholdMs` AND either:
|
|
4056
|
+
*
|
|
4057
|
+
* - it is suspended with NO wake timer (`wakeForever`): nothing will ever re-drive it; or
|
|
4058
|
+
* - its oldest pending REMOTE step is older than the threshold and has no lease in the future
|
|
4059
|
+
* (`stalePending`): the dispatch was most likely lost.
|
|
4060
|
+
*
|
|
4061
|
+
* Healthy long work is excluded: a long `ctx.sleep` has a future `wakeAt` and no pending step, and a
|
|
4062
|
+
* remote step with a `timeoutMs`, a heartbeat or `remoteRedispatchMs` carries a future lease. Issues
|
|
4063
|
+
* one `listCheckpoints` per idle candidate, bounded by `scan`: an operator read, not a hot path.
|
|
4064
|
+
*/
|
|
4065
|
+
declare function findStalledRuns(store: Pick<StateStore, 'listRuns' | 'listCheckpoints'>, options?: FindStalledRunsOptions): Promise<StalledRunInfo[]>;
|
|
4066
|
+
|
|
3946
4067
|
type WorkflowFn = (ctx: InternalWorkflowCtx, input: unknown) => Promise<unknown>;
|
|
3947
4068
|
/**
|
|
3948
4069
|
* Options for {@link WorkflowEngine.start}.
|
|
@@ -4119,6 +4240,14 @@ interface WorkflowEngineDeps {
|
|
|
4119
4240
|
* for a genuinely-orphaned run. Default 5min; set `0` to disable (the prior wake-forever behavior).
|
|
4120
4241
|
*/
|
|
4121
4242
|
reconcileMs?: number | undefined;
|
|
4243
|
+
/**
|
|
4244
|
+
* How long an in-flight run must sit untouched, with the stranded signature (a wake-forever
|
|
4245
|
+
* suspension, or an old pending remote step with no live lease), before the
|
|
4246
|
+
* {@link WorkflowEngine.onStalled} listeners are notified. Default 900 000 (15 min); floored at
|
|
4247
|
+
* 60 000. The sweep ({@link WorkflowEngine.sweepStalled}) only does work when a listener is
|
|
4248
|
+
* registered.
|
|
4249
|
+
*/
|
|
4250
|
+
stalledAfterMs?: number | undefined;
|
|
4122
4251
|
/**
|
|
4123
4252
|
* The most due timers one {@link WorkflowEngine.resumeDueTimers} pass loads and drives, most
|
|
4124
4253
|
* overdue first. Every driving instance runs that pass each tick, so a wave of thousands of due
|
|
@@ -4226,6 +4355,15 @@ interface WorkflowEngineDeps {
|
|
|
4226
4355
|
*/
|
|
4227
4356
|
runDispatcher?: RunDispatcher | undefined;
|
|
4228
4357
|
}
|
|
4358
|
+
/** Options for {@link WorkflowEngine.listStalledRuns}. */
|
|
4359
|
+
interface ListStalledRunsOptions {
|
|
4360
|
+
/** Idle threshold in ms. Defaults to the engine's `stalledAfterMs` (15 min). */
|
|
4361
|
+
thresholdMs?: number | undefined;
|
|
4362
|
+
/** Max candidate runs inspected (newest first). Default 1000. */
|
|
4363
|
+
scan?: number | undefined;
|
|
4364
|
+
/** Evaluate as of this clock time. Defaults to the engine clock. */
|
|
4365
|
+
now?: number | undefined;
|
|
4366
|
+
}
|
|
4229
4367
|
/**
|
|
4230
4368
|
* The orchestrator. Owns workflow state and replays runs deterministically: each step's
|
|
4231
4369
|
* result is checkpointed, so on resume a completed step returns its saved output instead of
|
|
@@ -4241,6 +4379,12 @@ declare class WorkflowEngine {
|
|
|
4241
4379
|
private readonly instanceId;
|
|
4242
4380
|
private readonly namespace;
|
|
4243
4381
|
private readonly leaseMs;
|
|
4382
|
+
/**
|
|
4383
|
+
* Leases held by this `instanceId` that expire strictly before this epoch ms were taken by a
|
|
4384
|
+
* PREVIOUS process with the same id (every lease this one takes or renews expires at
|
|
4385
|
+
* `clock() + leaseMs`, so at or after it). See {@link orphanedRuns}.
|
|
4386
|
+
*/
|
|
4387
|
+
private readonly ownLeaseCutoffMs;
|
|
4244
4388
|
private readonly maxRecoveryAttempts?;
|
|
4245
4389
|
private readonly remoteAdvanceSilenceMs?;
|
|
4246
4390
|
private readonly reconcileMs;
|
|
@@ -4344,6 +4488,18 @@ declare class WorkflowEngine {
|
|
|
4344
4488
|
private readonly stepQueue;
|
|
4345
4489
|
/** Executions currently in flight, so a graceful shutdown can wait for them to settle. */
|
|
4346
4490
|
private readonly inflight;
|
|
4491
|
+
/**
|
|
4492
|
+
* The run lease of each execution in flight on THIS instance, by run id — renewed while it runs
|
|
4493
|
+
* and checked by every settle (the zombie fence, see {@link ExecutionLease}). Also what `drain()`
|
|
4494
|
+
* releases when its budget runs out.
|
|
4495
|
+
*/
|
|
4496
|
+
private readonly executionLeases;
|
|
4497
|
+
/** Pager hooks for stranded runs (see {@link onStalled}). */
|
|
4498
|
+
private readonly stalledListeners;
|
|
4499
|
+
/** Runs already paged about, by id → the `updatedAt` of the paged episode (see {@link sweepStalled}). */
|
|
4500
|
+
private readonly notifiedStalled;
|
|
4501
|
+
private lastStalledSweepAt;
|
|
4502
|
+
private readonly stalledAfterMs;
|
|
4347
4503
|
private draining;
|
|
4348
4504
|
/** Wait already spent on this shutdown before `drain()` (see `beginDrain`). */
|
|
4349
4505
|
private drainSpentMs;
|
|
@@ -4509,6 +4665,33 @@ declare class WorkflowEngine {
|
|
|
4509
4665
|
* Returns an unsubscribe function.
|
|
4510
4666
|
*/
|
|
4511
4667
|
onDead(listener: (run: WorkflowRun) => void): () => void;
|
|
4668
|
+
/**
|
|
4669
|
+
* Register a pager hook for STRANDED runs: an in-flight run untouched past `stalledAfterMs` that is
|
|
4670
|
+
* either suspended with NO wake timer (wake-forever: nothing will ever re-drive it) or parked on an
|
|
4671
|
+
* old pending remote step with no live lease (dispatched and, most likely, lost). The timer poller
|
|
4672
|
+
* sweeps for these ({@link sweepStalled}, throttled to one pass a minute) and notifies each episode
|
|
4673
|
+
* ONCE per instance: a run is paged again only after it makes progress and strands again. Wire your
|
|
4674
|
+
* alerting here like {@link onDead}. A listener that throws never breaks the sweep. Returns an
|
|
4675
|
+
* unsubscribe function.
|
|
4676
|
+
*/
|
|
4677
|
+
onStalled(listener: (info: StalledRunInfo) => void): () => void;
|
|
4678
|
+
/**
|
|
4679
|
+
* Detect stranded in-flight runs and notify the {@link onStalled} listeners. Self-throttled to one
|
|
4680
|
+
* pass a minute, skipped while draining, and a no-op without listeners — call it every tick (the
|
|
4681
|
+
* NestJS timer poller does). Scoped to this engine's `namespace` (an operator engine with no
|
|
4682
|
+
* namespace sweeps every namespace). Returns the runs notified THIS pass.
|
|
4683
|
+
*/
|
|
4684
|
+
sweepStalled(now?: number): Promise<StalledRunInfo[]>;
|
|
4685
|
+
/**
|
|
4686
|
+
* The stranded runs right now, without notifying anyone: the query behind {@link sweepStalled} and
|
|
4687
|
+
* the CLI's `durable inspect --stale`. A `running`/`suspended` run qualifies when it has been
|
|
4688
|
+
* untouched for `thresholdMs` (default `stalledAfterMs`) AND either it is suspended with no wake
|
|
4689
|
+
* timer, or its oldest pending remote step is older than the threshold with no lease in the future
|
|
4690
|
+
* (a step with a `timeoutMs`, a heartbeat or `remoteRedispatchMs` keeps a lease; a long
|
|
4691
|
+
* `ctx.sleep` has a future `wakeAt`; neither is stranded). Scans up to `scan` candidates (default
|
|
4692
|
+
* 1000), newest first, in this engine's namespace.
|
|
4693
|
+
*/
|
|
4694
|
+
listStalledRuns(options?: ListStalledRunsOptions): Promise<StalledRunInfo[]>;
|
|
4512
4695
|
private notifyDead;
|
|
4513
4696
|
/** Emit a locally-produced lifecycle event: deliver to subscribers AND broadcast it on the
|
|
4514
4697
|
* control plane so other instances (e.g. a dashboard pod) can live-tail this run. */
|
|
@@ -4520,6 +4703,9 @@ declare class WorkflowEngine {
|
|
|
4520
4703
|
start<TInput>(workflow: string, input: TInput, runId: string, opts?: StartOptions): Promise<RunResult>;
|
|
4521
4704
|
/** Read a run's current persisted state (or null if unknown). A thin pass-through to the store. */
|
|
4522
4705
|
getRun(runId: string): Promise<WorkflowRun | null>;
|
|
4706
|
+
/** A run's full checkpoint timeline, ordered by seq. A thin pass-through to the store (it is what
|
|
4707
|
+
* the testing kit's `captureHistory` reads, next to {@link getRun}). */
|
|
4708
|
+
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
4523
4709
|
/**
|
|
4524
4710
|
* Re-execute a run's body (replaying its checkpoints). This is the EXPLICIT entry point: besides
|
|
4525
4711
|
* driving a live run, it re-drives a `failed` run — the manual retry (prefer {@link requeue}, which
|
|
@@ -4671,12 +4857,31 @@ declare class WorkflowEngine {
|
|
|
4671
4857
|
* for part of it waits only for the remainder. With nothing reported, the full `timeoutMs` applies.
|
|
4672
4858
|
*/
|
|
4673
4859
|
drain(timeoutMs?: number): Promise<void>;
|
|
4860
|
+
/**
|
|
4861
|
+
* The drain budget ran out with executions still in flight: release their recovery leases so
|
|
4862
|
+
* another instance re-drives those runs on its next recovery pass, instead of waiting out
|
|
4863
|
+
* `leaseMs` after this process exits. Each still-running turn is FENCED first, so whatever it
|
|
4864
|
+
* computes after this point is never written over the new owner's work (see settleRun). Its
|
|
4865
|
+
* completed steps are checkpointed, so the new owner replays them; a step still executing here
|
|
4866
|
+
* may run again there, exactly as after a crash. The release is owner-scoped where the store
|
|
4867
|
+
* supports it (only a lease this instance still holds is cleared). Best effort: never throws.
|
|
4868
|
+
*/
|
|
4869
|
+
private releaseInflightLeases;
|
|
4674
4870
|
/**
|
|
4675
4871
|
* Cancel in-flight runs that have outlived their workflow's `executionTimeout`. Call it from the
|
|
4676
4872
|
* timer poller alongside {@link resumeDueTimers}. A timed-out run is moved to `cancelled` with an
|
|
4677
4873
|
* `execution_timeout` error (terminal, so a late step result can't resurrect it), AND its children
|
|
4678
4874
|
* are cascaded exactly as an explicit {@link cancel} cascades them.
|
|
4679
4875
|
*
|
|
4876
|
+
* WHICH RUNS. Every run not yet finished, counted from `createdAt`: `pending` and `blocked` as well
|
|
4877
|
+
* as `running` and `suspended`. A run nobody picks up (no worker on its queue) or nobody can run (no
|
|
4878
|
+
* worker with its capabilities) is as stuck as one that hangs mid-body, and the cap is the backstop
|
|
4879
|
+
* for exactly that — leaving them out meant a run that never started lived forever while one that
|
|
4880
|
+
* started and hung was cut off. Cancelling one a worker is picking up at that moment is safe: the
|
|
4881
|
+
* worker's settle only writes over a live status ({@link SETTLE_ELIGIBLE_STATUSES}), so it can't
|
|
4882
|
+
* bring the run back. `cancelling` is left alone on purpose — a compensating cancel's saga undo is
|
|
4883
|
+
* running, it ends `cancelled` by itself, and cutting it short would skip the undo.
|
|
4884
|
+
*
|
|
4680
4885
|
* WHY THE TERMINAL WRITE IS DIRECT, not a call to {@link cancel}. Two reasons, both still standing:
|
|
4681
4886
|
* the run must land with the `execution_timeout` error `cancel` knows nothing about (`cancel` writes
|
|
4682
4887
|
* a plain `cancelled`, and the code is what a dashboard/alert distinguishes a timeout by), and this
|
|
@@ -4689,8 +4894,8 @@ declare class WorkflowEngine {
|
|
|
4689
4894
|
* children kept running with the parent gone and nothing pointing at them — a silent orphan you
|
|
4690
4895
|
* could only find by reading the runs table by hand. {@link cancelChildren} is the SAME recursive
|
|
4691
4896
|
* walk `cancel` uses, so children of children go too, and it inherits that path's two guards:
|
|
4692
|
-
* `cancel` returns early on a run that is already
|
|
4693
|
-
*
|
|
4897
|
+
* `cancel` returns early on a run that is already terminal (a child that beat the sweep to the
|
|
4898
|
+
* finish is never clobbered, and a re-cancel is a no-op), and it writes the
|
|
4694
4899
|
* parent's terminal status BEFORE recursing, so a cyclic parent→child graph terminates on the
|
|
4695
4900
|
* second visit instead of looping. Two pollers sweeping the same run concurrently therefore write
|
|
4696
4901
|
* the same terminal state twice and cascade into already-cancelled children — idempotent, not
|
|
@@ -4707,6 +4912,27 @@ declare class WorkflowEngine {
|
|
|
4707
4912
|
* replay from their checkpoints, so only the work that had not finished runs again.
|
|
4708
4913
|
*/
|
|
4709
4914
|
recoverIncomplete(nowMs?: number): Promise<RunResult[]>;
|
|
4915
|
+
/** A run whose still-live lease is held by this very `instanceId` (see {@link reclaimOwnLease}). */
|
|
4916
|
+
private isOwnLiveLease;
|
|
4917
|
+
/**
|
|
4918
|
+
* Recover a run whose lease is still live but held by THIS `instanceId` and predates this process
|
|
4919
|
+
* (listed by {@link orphanedRuns}): the previous process with this stable id died without a
|
|
4920
|
+
* graceful shutdown (OOM, SIGKILL), so nothing is renewing that lease and waiting for it to expire
|
|
4921
|
+
* only delays the run. The lease is taken back with `renewRunLock` (a compare-and-set on the
|
|
4922
|
+
* owner; `tryLockRun` refuses a live lease), so the lease alone cannot fence a live execution in
|
|
4923
|
+
* THIS process from its own recovery: the in-process run gate does. A run with a
|
|
4924
|
+
* gate is executing (or about to) here and is skipped; otherwise a gate is held while the run is
|
|
4925
|
+
* recovered, so a resume landing meanwhile queues behind the recovery instead of running beside it.
|
|
4926
|
+
* The gate is released before the re-dispatch, which may resume the run on this instance.
|
|
4927
|
+
*/
|
|
4928
|
+
private reclaimOwnLease;
|
|
4929
|
+
/**
|
|
4930
|
+
* One run of a {@link recoverIncomplete} pass: take its lease and decide on it. Resolves the
|
|
4931
|
+
* pass's result for it and whether it must be re-dispatched, or `undefined` when it was not ours.
|
|
4932
|
+
* `ownLease`: the run's live lease is this instance id's own, left by a previous process (see
|
|
4933
|
+
* {@link reclaimOwnLease}), so it is taken back by owner rather than acquired as a free one.
|
|
4934
|
+
*/
|
|
4935
|
+
private recoverOrphan;
|
|
4710
4936
|
/**
|
|
4711
4937
|
* The runs {@link recoverIncomplete} should try to reclaim: incomplete runs whose lease is free or
|
|
4712
4938
|
* expired, never the healthy ones a live turn is renewing. Every worker runs recovery on every
|
|
@@ -4715,6 +4941,10 @@ declare class WorkflowEngine {
|
|
|
4715
4941
|
* ({@link StateStore.listOrphanedRuns}, bounded by {@link RECOVERY_BATCH}); else the full list is
|
|
4716
4942
|
* filtered here, which still spares the probes. Shuffled, like the due-timer pass, so instances
|
|
4717
4943
|
* recovering at once spread over the batch instead of contending for the same leases.
|
|
4944
|
+
*
|
|
4945
|
+
* Also listed: runs still leased by THIS `instanceId` with a lease taken before this process
|
|
4946
|
+
* booted ({@link ownLeaseCutoffMs}). With a stable `instanceId` (pinned to the pod identity), that
|
|
4947
|
+
* is the previous process, killed without a graceful shutdown; see {@link reclaimOwnLease}.
|
|
4718
4948
|
*/
|
|
4719
4949
|
private orphanedRuns;
|
|
4720
4950
|
/**
|
|
@@ -4947,6 +5177,13 @@ declare class WorkflowEngine {
|
|
|
4947
5177
|
* side actually removes the row is the one that delivers, so a signal is never delivered twice.
|
|
4948
5178
|
*/
|
|
4949
5179
|
signal(token: string, payload: unknown): Promise<RunResult | null>;
|
|
5180
|
+
/**
|
|
5181
|
+
* Wake the run parked on `token` with `payload`, if there is one; otherwise do nothing — unlike
|
|
5182
|
+
* {@link signal}, it never buffers. For a wake-up whose real payload is ALREADY buffered on the
|
|
5183
|
+
* token (an entity op, see `Entities.kick`): a run that isn't parked reads that buffer at its next
|
|
5184
|
+
* wait, so there is nothing to keep.
|
|
5185
|
+
*/
|
|
5186
|
+
private wakeSignalWaiter;
|
|
4950
5187
|
/**
|
|
4951
5188
|
* Ensure a run exists for `runId`, then deliver a signal to it — atomically race-free thanks to
|
|
4952
5189
|
* signal buffering: if the run is new (or busy / not yet waiting), the signal is buffered and
|
|
@@ -5165,8 +5402,35 @@ declare class WorkflowEngine {
|
|
|
5165
5402
|
/** Checkpoint a step that failed terminally, so the failure point is visible (not just the run). */
|
|
5166
5403
|
private failStep;
|
|
5167
5404
|
/** Admission persists the wait atomically; never overwrite a cancellation after it returns. */
|
|
5405
|
+
/**
|
|
5406
|
+
* A run's first execution: `pending` -> `running`. A singleton run not yet admitted is stamped
|
|
5407
|
+
* {@link SINGLETON_TRACKED_TAG} in the same write, BEFORE it competes for a slot, so a run this
|
|
5408
|
+
* replica is about to admit or deny is never mistaken for a holder admitted by a replica older
|
|
5409
|
+
* than 0.73 (see `legacySingletonHolders`).
|
|
5410
|
+
*/
|
|
5411
|
+
private markStarted;
|
|
5168
5412
|
private singletonWaitResult;
|
|
5169
5413
|
private execute;
|
|
5414
|
+
/**
|
|
5415
|
+
* Renew `runId`'s lease for as long as this execution holds it, and register it in
|
|
5416
|
+
* {@link executionLeases} so settles can check the zombie fence and `drain()` can release it.
|
|
5417
|
+
*
|
|
5418
|
+
* A renewal that returns `false` means the lease is gone: this turn stalled past `leaseMs` and
|
|
5419
|
+
* another instance reclaimed the run, so this executor is now a zombie. It is FENCED (`lost`): its
|
|
5420
|
+
* settles degrade to an echo of the store's state instead of clobbering the new owner's writes, and
|
|
5421
|
+
* its own lease release is skipped (it would free the new owner's lease). A renewal that THROWS (a
|
|
5422
|
+
* transient store error) is not evidence of a takeover, so it stays swallowed and the next
|
|
5423
|
+
* interval retries. A lease this execution released on purpose (`handedOff`) is not renewed, and a
|
|
5424
|
+
* renewal resolving after the execution ended (`done`) fences nothing.
|
|
5425
|
+
*/
|
|
5426
|
+
private holdExecutionLease;
|
|
5427
|
+
/** Whether `runId`'s execution on this instance lost its lease (see {@link holdExecutionLease}). */
|
|
5428
|
+
private isFenced;
|
|
5429
|
+
/**
|
|
5430
|
+
* Mark `runId`'s lease as given away on purpose by its own execution (released mid-turn), so a
|
|
5431
|
+
* renewal that now fails is not read as a takeover.
|
|
5432
|
+
*/
|
|
5433
|
+
private handOffLease;
|
|
5170
5434
|
/**
|
|
5171
5435
|
* Advance a remote (cross-SDK) workflow one turn: hand its history to the executor (which dispatches
|
|
5172
5436
|
* a workflow task to the worker and awaits its replay) and apply the decision. Mirrors
|
|
@@ -5680,6 +5944,14 @@ declare class DurableWorkflow {
|
|
|
5680
5944
|
*/
|
|
5681
5945
|
declare function parseDuration(duration: string | number): number;
|
|
5682
5946
|
|
|
5947
|
+
/**
|
|
5948
|
+
* Format marker of a run-history replay fixture (`{ version, run, checkpoints }`). Written by the
|
|
5949
|
+
* testing kit's `serializeRunHistory` and the CLI's `durable export`, checked by `parseRunHistory`.
|
|
5950
|
+
* Lives in core so both writers (which already depend on core, not on each other) share one value.
|
|
5951
|
+
* Bump it only when the fixture shape changes incompatibly.
|
|
5952
|
+
*/
|
|
5953
|
+
declare const RUN_HISTORY_FIXTURE_VERSION = 1;
|
|
5954
|
+
|
|
5683
5955
|
/**
|
|
5684
5956
|
* Thrown inside a step to signal an unrecoverable failure: the engine will NOT retry it,
|
|
5685
5957
|
* regardless of the step's `retries` setting, and fails the run immediately. Use it for
|
|
@@ -6086,6 +6358,15 @@ declare function fanPageEtag(group: string, stats: CheckpointStat[], query: FanP
|
|
|
6086
6358
|
/** Whether an `If-None-Match` header value names `etag` (weak comparison, as RFC 9110 asks for). */
|
|
6087
6359
|
declare function etagMatches(ifNoneMatch: string | undefined, etag: string): boolean;
|
|
6088
6360
|
|
|
6361
|
+
/**
|
|
6362
|
+
* Split a `ctx.webhook()` token (`wh:<runId>:<seq>`) into its run id and logical position, or `null`
|
|
6363
|
+
* for any other token. The run id may itself contain `:` (an entity run is `entity:<name>:<key>`), so
|
|
6364
|
+
* the seq is the LAST segment.
|
|
6365
|
+
*/
|
|
6366
|
+
declare function parseWebhookToken(token: string): {
|
|
6367
|
+
runId: string;
|
|
6368
|
+
seq: number;
|
|
6369
|
+
} | null;
|
|
6089
6370
|
/**
|
|
6090
6371
|
* Resolve WHAT a suspended run is parked on from the token of the {@link SignalWaiter} it registered.
|
|
6091
6372
|
* The token prefix carries the kind — no extra store lookup and no new persisted field. Used by the
|
|
@@ -6133,26 +6414,45 @@ interface PayloadCodec {
|
|
|
6133
6414
|
encode(value: unknown): unknown;
|
|
6134
6415
|
decode(value: unknown): unknown;
|
|
6135
6416
|
}
|
|
6417
|
+
/** What {@link CodecStateStore} runs through the codec. */
|
|
6418
|
+
interface CodecStateStoreOptions {
|
|
6419
|
+
/**
|
|
6420
|
+
* `'payloads'` (default, the historical behaviour): run/step `input` + `output` only (plus a
|
|
6421
|
+
* schedule's `input` and buffered signal/event payloads, which are always encoded). **Know what
|
|
6422
|
+
* that leaves in the clear**: step `events` (everything step code passes to `ctx.log` and every
|
|
6423
|
+
* sub-step outcome) and the structured step/run `error` (message, stack, details). A deployment
|
|
6424
|
+
* sold as "encrypted payloads" still leaks whatever its steps log or throw.
|
|
6425
|
+
*
|
|
6426
|
+
* `'extended'`: also encode step `events`, step `error` and run `error`. Searchable metadata (ids,
|
|
6427
|
+
* status, workflow, tags, search attributes, namespace, origin, timestamps) stays clear — it must
|
|
6428
|
+
* remain queryable. ONLY enable on a FRESH table, or with a codec whose `decode` recognizes its own
|
|
6429
|
+
* ciphertext and passes other values through: rows written before the switch hold those fields as
|
|
6430
|
+
* plaintext, and a decode that can't tell would garble them.
|
|
6431
|
+
*/
|
|
6432
|
+
coverage?: 'payloads' | 'extended';
|
|
6433
|
+
}
|
|
6136
6434
|
/**
|
|
6137
|
-
* A `StateStore` decorator that runs run/step **payloads**
|
|
6138
|
-
*
|
|
6139
|
-
*
|
|
6140
|
-
*
|
|
6435
|
+
* A `StateStore` decorator that runs run/step **payloads** through a {@link PayloadCodec} — encoded
|
|
6436
|
+
* on write, decoded on read — so they're never stored in the clear. Adapter-agnostic: wrap any
|
|
6437
|
+
* store. Searchable metadata (id, status, workflow, tags, timestamps) is left untouched so the
|
|
6438
|
+
* dashboard, queries, and recovery still work. See {@link CodecStateStoreOptions.coverage} for
|
|
6439
|
+
* exactly which fields are covered — the default covers `input`/`output` only.
|
|
6141
6440
|
*
|
|
6142
6441
|
* ```ts
|
|
6143
|
-
* const store = new CodecStateStore(new TypeOrmStateStore(ds), aesCodec);
|
|
6442
|
+
* const store = new CodecStateStore(new TypeOrmStateStore(ds), aesCodec, { coverage: 'extended' });
|
|
6144
6443
|
* ```
|
|
6145
6444
|
*/
|
|
6146
6445
|
declare class CodecStateStore implements StateStore {
|
|
6147
6446
|
private readonly inner;
|
|
6148
6447
|
private readonly codec;
|
|
6448
|
+
private readonly extended;
|
|
6149
6449
|
/** Atomic claims touch only searchable metadata and bypass payload encoding. */
|
|
6150
6450
|
readonly tryAdmitSingleton?: (runId: string, tag: string, workflow: string, limit: number, retryWakeAt?: number) => Promise<boolean>;
|
|
6151
6451
|
/**
|
|
6152
6452
|
* Forwarded verbatim — a facet cell counts `status`/`origin`, neither of which the codec touches
|
|
6153
|
-
* (it encodes payloads: input/output/error). Bound as a
|
|
6154
|
-
* actually aggregates, so `store.runFacets?.()` still
|
|
6155
|
-
* of resolving to a silently wrong empty result.
|
|
6453
|
+
* (it encodes payloads: input/output, plus events/error under `extended` coverage). Bound as a
|
|
6454
|
+
* PROPERTY, and only when the inner store actually aggregates, so `store.runFacets?.()` still
|
|
6455
|
+
* reports absence through the wrapper instead of resolving to a silently wrong empty result.
|
|
6156
6456
|
*/
|
|
6157
6457
|
readonly runFacets?: (query: RunFacetQuery) => Promise<RunFacetRow[]>;
|
|
6158
6458
|
/**
|
|
@@ -6166,7 +6466,7 @@ declare class CodecStateStore implements StateStore {
|
|
|
6166
6466
|
readonly deleteRuns?: (runIds: string[]) => Promise<void>;
|
|
6167
6467
|
/** Decodes the runs like {@link listIncompleteRuns}. Bound only when the inner store has it, so
|
|
6168
6468
|
* the engine's list-and-filter fallback still kicks in through the wrapper. */
|
|
6169
|
-
readonly listOrphanedRuns?: (nowMs: number, limit: number, namespace?: string) => Promise<WorkflowRun[]>;
|
|
6469
|
+
readonly listOrphanedRuns?: (nowMs: number, limit: number, namespace?: string, ownedBy?: OwnedLeaseReclaim) => Promise<WorkflowRun[]>;
|
|
6170
6470
|
/** Encodes the patch like {@link updateRun}. Bound only when the inner store has it, so the
|
|
6171
6471
|
* engine's read-then-write fallback still kicks in through the wrapper. */
|
|
6172
6472
|
readonly updateRunIf?: (runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>) => Promise<boolean>;
|
|
@@ -6206,7 +6506,7 @@ declare class CodecStateStore implements StateStore {
|
|
|
6206
6506
|
readonly updateSchedule?: (id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null) => Promise<boolean>;
|
|
6207
6507
|
readonly deleteSchedule?: (id: string) => Promise<boolean>;
|
|
6208
6508
|
readonly listSchedules?: (query: ScheduleQuery) => Promise<ScheduleRecord[]>;
|
|
6209
|
-
constructor(inner: StateStore, codec: PayloadCodec);
|
|
6509
|
+
constructor(inner: StateStore, codec: PayloadCodec, options?: CodecStateStoreOptions);
|
|
6210
6510
|
private enc;
|
|
6211
6511
|
private dec;
|
|
6212
6512
|
private encRun;
|
|
@@ -6232,7 +6532,7 @@ declare class CodecStateStore implements StateStore {
|
|
|
6232
6532
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
6233
6533
|
listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;
|
|
6234
6534
|
tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
|
|
6235
|
-
releaseRunLock(runId: string): Promise<void>;
|
|
6535
|
+
releaseRunLock(runId: string, owner?: string): Promise<void>;
|
|
6236
6536
|
renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean>;
|
|
6237
6537
|
putSignalWaiter(waiter: SignalWaiter): Promise<void>;
|
|
6238
6538
|
takeSignalWaiter(token: string): Promise<SignalWaiter | null>;
|
|
@@ -6669,12 +6969,12 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
6669
6969
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
6670
6970
|
saveCheckpointIfPending(checkpoint: StepCheckpoint): Promise<boolean>;
|
|
6671
6971
|
saveCheckpointsIfPending(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
|
|
6672
|
-
listOrphanedRuns(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
6972
|
+
listOrphanedRuns(nowMs: number, limit: number, namespace?: string, ownedBy?: OwnedLeaseReclaim): Promise<WorkflowRun[]>;
|
|
6673
6973
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
6674
6974
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
6675
6975
|
listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;
|
|
6676
6976
|
tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
|
|
6677
|
-
releaseRunLock(runId: string): Promise<void>;
|
|
6977
|
+
releaseRunLock(runId: string, owner?: string): Promise<void>;
|
|
6678
6978
|
renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean>;
|
|
6679
6979
|
putSignalWaiter(waiter: SignalWaiter): Promise<void>;
|
|
6680
6980
|
takeSignalWaiter(token: string): Promise<SignalWaiter | null>;
|
|
@@ -6769,7 +7069,42 @@ declare class InMemoryTransport implements Transport, ControlPlane {
|
|
|
6769
7069
|
|
|
6770
7070
|
/** Reserved engine metadata: a durable singleton slot, independent of the execution lease. */
|
|
6771
7071
|
declare const SINGLETON_ADMITTED_TAG = "durable:singleton:admitted";
|
|
7072
|
+
/**
|
|
7073
|
+
* Reserved engine metadata: this not-yet-admitted run's admission is decided by the tag scheme, so
|
|
7074
|
+
* it holds no slot unless it carries {@link SINGLETON_ADMITTED_TAG}. Stamped on a run's first
|
|
7075
|
+
* execution (`pending` -> `running`) and on every denial. An untagged run WITHOUT it that a
|
|
7076
|
+
* replica has executed was executed by a replica older than 0.73: see
|
|
7077
|
+
* {@link legacySingletonHolders}. Admission and terminal settlement remove it.
|
|
7078
|
+
*/
|
|
7079
|
+
declare const SINGLETON_TRACKED_TAG = "durable:singleton:tracked";
|
|
7080
|
+
/** Tags only the engine/store may write; stripped from user-supplied start tags. */
|
|
7081
|
+
declare const SINGLETON_RESERVED_TAGS: readonly string[];
|
|
6772
7082
|
declare const SINGLETON_ACTIVE_STATUSES: RunStatus[];
|
|
7083
|
+
/** `tags` without the engine's singleton admission metadata. */
|
|
7084
|
+
declare function withoutSingletonMarkers(tags: string[] | undefined): string[] | undefined;
|
|
7085
|
+
/** `tags` carrying {@link SINGLETON_TRACKED_TAG} (unchanged when admitted or already tracked). */
|
|
7086
|
+
declare function withSingletonTracked(tags: string[] | undefined): string[];
|
|
7087
|
+
/**
|
|
7088
|
+
* The runs other than `runId` that may hold a slot of this key WITHOUT carrying
|
|
7089
|
+
* {@link SINGLETON_ADMITTED_TAG}: holders admitted by a replica older than 0.73, during a rolling
|
|
7090
|
+
* upgrade that mixes old and new replicas.
|
|
7091
|
+
*
|
|
7092
|
+
* Old replicas admit by a scan: a run may execute when it is among the `limit` oldest
|
|
7093
|
+
* `running`/`suspended`/`cancelling` runs sharing the key, by `(createdAt, id)`, and they write no
|
|
7094
|
+
* tag. Among those statuses, an untagged run counts as a legacy holder when either:
|
|
7095
|
+
*
|
|
7096
|
+
* - it lacks {@link SINGLETON_TRACKED_TAG}. A new replica stamps that marker on a run's first
|
|
7097
|
+
* execution and on every denial, so an untagged executed run without it was executed (admitted)
|
|
7098
|
+
* by an old replica. A denial alone cannot be told apart from a holder (both old and new denials
|
|
7099
|
+
* park the run `suspended` with a retry `wakeAt`, exactly like a holder sleeping in `ctx.sleep`),
|
|
7100
|
+
* which is why the marker exists. Waiters an old replica parked count too until a new replica
|
|
7101
|
+
* re-checks them (one retry, ~1s), which only delays, never over-admits.
|
|
7102
|
+
* - it sits inside the old scan's own window (the `limit` oldest of those runs). An old replica can
|
|
7103
|
+
* admit a run a new replica had marked, without clearing the marker; the window is what it
|
|
7104
|
+
* admitted it on. Without old replicas this never changes a `limit: 1` decision (a run inside the
|
|
7105
|
+
* window is the head of the FIFO, admitted next anyway); with a larger limit it can only delay one.
|
|
7106
|
+
*/
|
|
7107
|
+
declare function legacySingletonHolders(active: WorkflowRun[], runId: string, limit: number): WorkflowRun[];
|
|
6773
7108
|
/** Call only inside a store's atomic admission transaction/critical section. */
|
|
6774
7109
|
declare function singletonAdmissionTags(runs: WorkflowRun[], runId: string, tag: string, workflow: string, limit: number): string[] | null;
|
|
6775
7110
|
/** Terminal runs release admission, including when later resumed directly rather than requeued. */
|
|
@@ -6778,7 +7113,8 @@ declare function clearTerminalSingletonAdmission(runId: string, patch: Partial<W
|
|
|
6778
7113
|
declare function singletonAdmissionDenialPatch(runs: WorkflowRun[], runId: string, tag: string, workflow: string, retryWakeAt?: number): {
|
|
6779
7114
|
status: 'suspended';
|
|
6780
7115
|
wakeAt: number;
|
|
7116
|
+
tags: string[];
|
|
6781
7117
|
updatedAt: Date;
|
|
6782
7118
|
} | undefined;
|
|
6783
7119
|
|
|
6784
|
-
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduledRunId, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, workflowName };
|
|
7120
|
+
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type CodecStateStoreOptions, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DEFAULT_STALLED_AFTER_MS, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, ENTITY_WORKFLOW, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, type EntityWorkflowHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, type FindStalledRunsOptions, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type ListStalledRunsOptions, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type OwnedLeaseReclaim, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_HISTORY_FIXTURE_VERSION, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, SINGLETON_RESERVED_TAGS, SINGLETON_TRACKED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, type StalePendingStep, type StalledRunInfo, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, findStalledRuns, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, legacySingletonHolders, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, parseWebhookToken, partitionOfToken, planDispatch, poolNamespace, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduledRunId, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, withSingletonTracked, withoutSingletonMarkers, workflowName };
|