@dudousxd/nestjs-durable-core 0.71.1 → 0.72.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 +976 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +514 -2
- package/dist/index.d.ts +514 -2
- package/dist/index.js +961 -171
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -935,10 +935,23 @@ interface StateStore {
|
|
|
935
935
|
* first), cascading to their child rows exactly like {@link deleteRun}. Returns how many runs were
|
|
936
936
|
* deleted — call again while it returns `limit` to drain a large backlog in bounded batches.
|
|
937
937
|
*
|
|
938
|
+
* A policy with a {@link RetentionPolicy.scope} only ever selects (and counts, for `maxCount`) runs
|
|
939
|
+
* matching that scope.
|
|
940
|
+
*
|
|
938
941
|
* Optional: only adapters that implement a bulk prune provide it; the retention poller no-ops with a
|
|
939
942
|
* warning when the configured store omits it. See {@link RetentionPolicy} for the keep/prune rule.
|
|
940
943
|
*/
|
|
941
944
|
pruneTerminalRuns?(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
|
|
945
|
+
/**
|
|
946
|
+
* Hard-delete a BATCH of runs and all of their rows in one go — exactly {@link deleteRun} applied to
|
|
947
|
+
* every id (checkpoints, signal waiters, attribute rows, then the runs), but as a handful of
|
|
948
|
+
* `IN (...)` statements in one transaction instead of four round-trips per run. Ids that don't exist
|
|
949
|
+
* are ignored. Like {@link deleteRun} it removes exactly the listed runs; the engine's
|
|
950
|
+
* `purgeRuns` walks the child edges first.
|
|
951
|
+
*
|
|
952
|
+
* Optional: a store that omits it still works — the engine falls back to one {@link deleteRun} per id.
|
|
953
|
+
*/
|
|
954
|
+
deleteRuns?(runIds: string[]): Promise<void>;
|
|
942
955
|
getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
|
|
943
956
|
/**
|
|
944
957
|
* Persist a checkpoint and advance the run atomically. Durable semantics depend on this
|
|
@@ -1031,7 +1044,30 @@ interface StateStore {
|
|
|
1031
1044
|
* adapters implement it; `ctx.transaction` errors on a store without it.
|
|
1032
1045
|
*/
|
|
1033
1046
|
transaction?<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T>;
|
|
1047
|
+
/** Insert or fully replace the schedule `record.id`. */
|
|
1048
|
+
saveSchedule?(record: ScheduleRecord): Promise<void>;
|
|
1049
|
+
/** The schedule `id`, or null. */
|
|
1050
|
+
getSchedule?(id: string): Promise<ScheduleRecord | null>;
|
|
1051
|
+
/**
|
|
1052
|
+
* Patch the schedule `id`. With `expectedNextFireAt`, a compare-and-set: the patch applies only if
|
|
1053
|
+
* the stored `nextFireAt` still equals it (`null` matching `NULL`), which is how two schedulers racing
|
|
1054
|
+
* on the same due schedule agree on who advanced it. Returns whether a row was updated.
|
|
1055
|
+
*/
|
|
1056
|
+
updateSchedule?(id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null): Promise<boolean>;
|
|
1057
|
+
/** Delete the schedule `id`. Returns whether it existed. Its past runs are left alone. */
|
|
1058
|
+
deleteSchedule?(id: string): Promise<boolean>;
|
|
1059
|
+
/** Schedules matching `query`, ordered by `nextFireAt` ascending (never-firing last), then `id`. */
|
|
1060
|
+
listSchedules?(query: ScheduleQuery): Promise<ScheduleRecord[]>;
|
|
1034
1061
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
1062
|
+
/**
|
|
1063
|
+
* How many runs match `query` — a single `COUNT(*)` over the same predicates {@link listRuns}
|
|
1064
|
+
* applies, without materializing a row. What the start-time concurrency quota asks on every start
|
|
1065
|
+
* (`tag = concurrency:<key> AND status IN (...)`), so it must stay an aggregate, not a listing.
|
|
1066
|
+
*
|
|
1067
|
+
* Optional: a store that omits it still works — the engine falls back to summing {@link runFacets}
|
|
1068
|
+
* cells, then to counting a {@link listRuns} result.
|
|
1069
|
+
*/
|
|
1070
|
+
countRuns?(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
|
|
1035
1071
|
/**
|
|
1036
1072
|
* Count the runs matching `query`, grouped by `(status, origin)` — the totals behind a console's
|
|
1037
1073
|
* status and origin chips, in ONE aggregate instead of a full listing the caller counts in memory.
|
|
@@ -1080,6 +1116,44 @@ interface StateStore {
|
|
|
1080
1116
|
*/
|
|
1081
1117
|
listCheckpointsByNamePrefix?(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
|
|
1082
1118
|
}
|
|
1119
|
+
/**
|
|
1120
|
+
* A persisted schedule as the STORE sees it: a handful of queryable columns plus two JSON documents
|
|
1121
|
+
* the store keeps verbatim (`spec`, `state`) and never interprets. The engine's schedule client owns
|
|
1122
|
+
* their meaning (cron/interval math, overlap, catch-up) — so a store only has to persist rows and
|
|
1123
|
+
* answer "which unpaused schedules are due by T".
|
|
1124
|
+
*/
|
|
1125
|
+
interface ScheduleRecord {
|
|
1126
|
+
/** Caller-chosen, stable id (e.g. `digest:user-42`) — also part of every run id it starts. */
|
|
1127
|
+
id: string;
|
|
1128
|
+
/** Partition: the namespace its runs are stamped with, and which schedulers fire it. */
|
|
1129
|
+
namespace: string;
|
|
1130
|
+
/** Registered workflow name the schedule starts. */
|
|
1131
|
+
workflow: string;
|
|
1132
|
+
/** A paused schedule is never due. */
|
|
1133
|
+
paused: boolean;
|
|
1134
|
+
/** Epoch ms at which it is next due (jitter included), or null when it will never fire again. */
|
|
1135
|
+
nextFireAt: number | null;
|
|
1136
|
+
/** Labels to list/filter schedules by (also stamped onto the runs it starts). */
|
|
1137
|
+
tags?: string[] | undefined;
|
|
1138
|
+
/** The schedule's definition — opaque to the store. */
|
|
1139
|
+
spec: Record<string, unknown>;
|
|
1140
|
+
/** The schedule's bookkeeping (last fire, last run id, last error…) — opaque to the store. */
|
|
1141
|
+
state: Record<string, unknown>;
|
|
1142
|
+
createdAt: Date;
|
|
1143
|
+
updatedAt: Date;
|
|
1144
|
+
}
|
|
1145
|
+
/** Filter for {@link StateStore.listSchedules}. Every predicate is ANDed; absent = unrestricted. */
|
|
1146
|
+
interface ScheduleQuery {
|
|
1147
|
+
namespace?: string | undefined;
|
|
1148
|
+
workflow?: string | undefined;
|
|
1149
|
+
/** Only schedules carrying this tag. */
|
|
1150
|
+
tag?: string | undefined;
|
|
1151
|
+
paused?: boolean | undefined;
|
|
1152
|
+
/** Only DUE schedules: unpaused, `nextFireAt <= dueBy`. */
|
|
1153
|
+
dueBy?: number | undefined;
|
|
1154
|
+
limit?: number | undefined;
|
|
1155
|
+
offset?: number | undefined;
|
|
1156
|
+
}
|
|
1083
1157
|
/** The terminal run statuses — a run in one of these is finished and will never change on its own.
|
|
1084
1158
|
* Only these are eligible for retention pruning (a {@link RetentionPolicy} targeting a non-terminal
|
|
1085
1159
|
* status would race the engine and delete live work). */
|
|
@@ -1100,7 +1174,27 @@ interface RetentionPolicy {
|
|
|
1100
1174
|
statuses: RunStatus[];
|
|
1101
1175
|
maxAge?: number | string;
|
|
1102
1176
|
maxCount?: number;
|
|
1177
|
+
/**
|
|
1178
|
+
* Confine the policy to the runs matching these predicates (same semantics as the {@link RunQuery}
|
|
1179
|
+
* fields of the same names) — e.g. `{ namespace: 'acme' }` for one tenant, `{ tags: ['chat'] }` for
|
|
1180
|
+
* one kind of run, `{ workflows: ['report', 'report.branch'] }` for a workflow family. Absent = every
|
|
1181
|
+
* run in `statuses`. `maxCount` is then counted WITHIN the scope ("keep acme's newest 100").
|
|
1182
|
+
*
|
|
1183
|
+
* A scope matches runs by their own row, so a child run is only covered if it matches too (children
|
|
1184
|
+
* inherit their parent's `namespace`, but not its `tags`) — scope by `namespace` or by `workflows`
|
|
1185
|
+
* when a whole run tree must age out together.
|
|
1186
|
+
*/
|
|
1187
|
+
scope?: RunScope | undefined;
|
|
1103
1188
|
}
|
|
1189
|
+
/**
|
|
1190
|
+
* The run predicates a bulk operation (a scoped {@link RetentionPolicy}, `engine.purgeRuns`) is
|
|
1191
|
+
* confined to — the identity axes of a {@link RunQuery}: which tenant (`namespace`), which kind of
|
|
1192
|
+
* run (`workflow`/`tags`), which business entity (`attributes`). Status, origin and paging are left
|
|
1193
|
+
* out on purpose: each bulk operation owns its own status rule.
|
|
1194
|
+
*/
|
|
1195
|
+
type RunScope = Pick<RunQuery, 'workflow' | 'workflows' | 'tag' | 'tags' | 'namespace' | 'namespaces' | 'attributes'>;
|
|
1196
|
+
/** True when `scope` sets at least one predicate — a bulk delete refuses an empty (match-all) scope. */
|
|
1197
|
+
declare function isNonEmptyRunScope(scope: RunScope | undefined): boolean;
|
|
1104
1198
|
/** Typed, queryable per-run data — exact values for `eq`/`ne`, numbers/strings for range ops. */
|
|
1105
1199
|
type SearchAttributes = Record<string, string | number | boolean>;
|
|
1106
1200
|
/**
|
|
@@ -2280,6 +2374,41 @@ interface WorkflowCtx<A extends SearchAttributes = SearchAttributes> {
|
|
|
2280
2374
|
*/
|
|
2281
2375
|
localStep<TOutput>(name: string, fn: (log: StepLogger) => Promise<TOutput>, options?: StepOptions): Promise<TOutput>;
|
|
2282
2376
|
}
|
|
2377
|
+
/**
|
|
2378
|
+
* {@link WorkflowCtx} with ONE signature per method: the string-addressed forms of the four overloaded
|
|
2379
|
+
* methods (`step`, `child`, `startChild`, `all`), everything else unchanged.
|
|
2380
|
+
*
|
|
2381
|
+
* For code that drives the ctx DYNAMICALLY — an interpreter that runs a user-defined graph and only
|
|
2382
|
+
* ever knows workflow/step names as strings — and for test fakes. An overloaded method is awkward to
|
|
2383
|
+
* satisfy structurally (a fake must implement every overload, and a hand-written narrow interface
|
|
2384
|
+
* has to guess which overload TS will match), so depend on this instead:
|
|
2385
|
+
*
|
|
2386
|
+
* ```ts
|
|
2387
|
+
* type InterpreterCtx = Pick<DynamicWorkflowCtx, 'runId' | 'localStep' | 'child' | 'all' | 'sleep'>;
|
|
2388
|
+
* class Interpreter { constructor(private readonly ctx: InterpreterCtx) {} }
|
|
2389
|
+
*
|
|
2390
|
+
* async run(ctx: WorkflowCtx, input: Input) {
|
|
2391
|
+
* return new Interpreter(ctx).run(); // no cast — a WorkflowCtx IS a DynamicWorkflowCtx
|
|
2392
|
+
* }
|
|
2393
|
+
* ```
|
|
2394
|
+
*
|
|
2395
|
+
* Every `WorkflowCtx<A>` is assignable to `DynamicWorkflowCtx<A>` (guarded by
|
|
2396
|
+
* `dynamic-workflow-ctx.type-test.ts`), and a `Pick` of it is a plain object literal in a test.
|
|
2397
|
+
*/
|
|
2398
|
+
interface DynamicWorkflowCtx<A extends SearchAttributes = SearchAttributes> extends Omit<WorkflowCtx<A>, 'step' | 'child' | 'startChild' | 'all'> {
|
|
2399
|
+
/** {@link WorkflowCtx.step} by step name (a cross-runtime handler, or a `@Step` by its name). */
|
|
2400
|
+
step<TOutput = unknown, TInput = unknown>(name: string, input: TInput, opts?: StepDispatchOpts & {
|
|
2401
|
+
compensate?: string;
|
|
2402
|
+
}): Promise<TOutput>;
|
|
2403
|
+
/** {@link WorkflowCtx.child} by workflow name. */
|
|
2404
|
+
child<TOutput = unknown>(workflow: string, input: unknown, options?: string | ChildCallOptions): Promise<TOutput>;
|
|
2405
|
+
/** {@link WorkflowCtx.startChild} by workflow name. */
|
|
2406
|
+
startChild(workflow: string, input: unknown, options?: string | ChildCallOptions): Promise<string>;
|
|
2407
|
+
/** {@link WorkflowCtx.all} by workflow name. */
|
|
2408
|
+
all<TOutput = unknown>(workflow: string, inputs: unknown[], opts?: {
|
|
2409
|
+
mode?: 'waitAll' | 'failFast';
|
|
2410
|
+
}): Promise<TOutput[]>;
|
|
2411
|
+
}
|
|
2283
2412
|
/** Result of executing or resuming a workflow run. */
|
|
2284
2413
|
interface RunResult {
|
|
2285
2414
|
runId: string;
|
|
@@ -2376,6 +2505,32 @@ declare function runInWorkflowCtx<T>(ctx: WorkflowCtx, fn: () => T): T;
|
|
|
2376
2505
|
* ambient workflow context (by design — a handler is not the workflow body).
|
|
2377
2506
|
*/
|
|
2378
2507
|
declare function currentWorkflowCtx(): WorkflowCtx | undefined;
|
|
2508
|
+
/**
|
|
2509
|
+
* The ambient STEP scope: which workflow ctx's checkpointed step body (if any) is executing on this
|
|
2510
|
+
* async path. The engine installs it around every in-body step execution (`ctx.localStep`,
|
|
2511
|
+
* `ctx.transaction`, and everything built on them) so the ctx primitives can refuse to run from
|
|
2512
|
+
* inside a step body — see {@link NestedWorkflowCallError}. `owner` is the identity of the ctx whose
|
|
2513
|
+
* step is running, so a DIFFERENT run's body executed inline from a step (e.g. a step that signals a
|
|
2514
|
+
* run which resumes on this async path) is never mistaken for a nested call.
|
|
2515
|
+
*
|
|
2516
|
+
* Shared per process under a `Symbol.for` key, for the same duplicate-copy reason as the ctx storage.
|
|
2517
|
+
*/
|
|
2518
|
+
interface StepScope {
|
|
2519
|
+
readonly owner: object;
|
|
2520
|
+
readonly step: string;
|
|
2521
|
+
}
|
|
2522
|
+
/** Run `fn` as the body of step `step` of the ctx identified by `owner`. Engine-internal. */
|
|
2523
|
+
declare function runInStepScope<T>(owner: object, step: string, fn: () => T): T;
|
|
2524
|
+
/** The step body currently executing on this async path, or `undefined` outside one. */
|
|
2525
|
+
declare function currentStepScope(): StepScope | undefined;
|
|
2526
|
+
/**
|
|
2527
|
+
* Run `fn` with NO ambient workflow ctx and no step scope — for a dispatched `@Step` handler. A
|
|
2528
|
+
* handler is not the workflow body (on a remote worker it never sees one), but an in-process
|
|
2529
|
+
* transport invokes it on the body's async path, where the parent's ctx would otherwise leak in and
|
|
2530
|
+
* turn a handler's `MyWorkflow.start()` into a journal-corrupting `ctx.startChild` of a parent that
|
|
2531
|
+
* is already suspended. Clearing it makes in-process and remote handlers behave identically.
|
|
2532
|
+
*/
|
|
2533
|
+
declare function runOutsideWorkflowCtx<T>(fn: () => T): T;
|
|
2379
2534
|
|
|
2380
2535
|
/**
|
|
2381
2536
|
* Run `fn` with `logger` as the ambient step logger. Engine-internal: wraps every execution of a
|
|
@@ -2490,6 +2645,60 @@ declare const CONTROL_FLOW_SIGNAL: unique symbol;
|
|
|
2490
2645
|
*/
|
|
2491
2646
|
declare function isWorkflowControlFlowSignal(error: unknown): boolean;
|
|
2492
2647
|
|
|
2648
|
+
/**
|
|
2649
|
+
* A start-time concurrency quota for ONE start: at most `limit` runs sharing `key` may be in flight
|
|
2650
|
+
* (in `countStatuses`) at once; a start that would exceed it is rejected with
|
|
2651
|
+
* {@link ConcurrencyLimitError} before any run is created.
|
|
2652
|
+
*
|
|
2653
|
+
* The key is global — not per workflow — so different workflows started with the same key share the
|
|
2654
|
+
* quota (e.g. `tenant:acme` capping every kind of run a tenant can have executing). Passed per start
|
|
2655
|
+
* as `StartOptions.concurrency`, or derived from the input by a workflow's {@link ConcurrencyConfig}.
|
|
2656
|
+
*/
|
|
2657
|
+
interface ConcurrencyQuota {
|
|
2658
|
+
/** The quota bucket, e.g. `tenant:acme`. Stamped on the run as the tag `concurrency:<key>`. */
|
|
2659
|
+
key: string;
|
|
2660
|
+
/** Max runs of this key in flight at once. `limit <= 0` rejects every start. */
|
|
2661
|
+
limit: number;
|
|
2662
|
+
/**
|
|
2663
|
+
* Which statuses occupy a slot. Default: every non-terminal status
|
|
2664
|
+
* ({@link DEFAULT_CONCURRENCY_STATUSES}). Narrow it to e.g. `['pending', 'running']` so runs parked
|
|
2665
|
+
* on a human (`suspended`) stop counting against the quota.
|
|
2666
|
+
*/
|
|
2667
|
+
countStatuses?: RunStatus[] | undefined;
|
|
2668
|
+
}
|
|
2669
|
+
/**
|
|
2670
|
+
* A workflow's standing concurrency quota, declared at registration (`register(..., { concurrency })`
|
|
2671
|
+
* / `@Workflow({ concurrency })`): the key is derived from each start's input, and the limit may be a
|
|
2672
|
+
* function of the key (per-tenant plans). A `StartOptions.concurrency` on one start overrides it.
|
|
2673
|
+
*/
|
|
2674
|
+
interface ConcurrencyConfig {
|
|
2675
|
+
/** Derive the quota key from the input. Return `undefined` to leave this start unlimited. */
|
|
2676
|
+
key: (input: unknown) => string | undefined;
|
|
2677
|
+
/** Max in-flight runs per key — a number, or resolved per key (e.g. from the tenant's plan). */
|
|
2678
|
+
limit: number | ((key: string) => number | Promise<number>);
|
|
2679
|
+
/** Which statuses occupy a slot. See {@link ConcurrencyQuota.countStatuses}. */
|
|
2680
|
+
countStatuses?: RunStatus[] | undefined;
|
|
2681
|
+
}
|
|
2682
|
+
/** Every non-terminal status: what "in flight" means when a quota doesn't narrow it. */
|
|
2683
|
+
declare const DEFAULT_CONCURRENCY_STATUSES: readonly RunStatus[];
|
|
2684
|
+
/** The tag a quota-bearing run carries, so its siblings can be counted by one tag+status query. */
|
|
2685
|
+
declare function concurrencyTag(key: string): string;
|
|
2686
|
+
/** Resolve the quota that applies to one start: the per-start override, else the workflow's config. */
|
|
2687
|
+
declare function resolveConcurrency(override: ConcurrencyQuota | undefined, config: ConcurrencyConfig | undefined, input: unknown): Promise<ConcurrencyQuota | undefined>;
|
|
2688
|
+
/** Count the runs matching `query` as cheaply as the store allows (count → facets → listing). */
|
|
2689
|
+
declare function countRuns(store: StateStore, query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
|
|
2690
|
+
/**
|
|
2691
|
+
* Reject a start that would exceed `quota`: counts the in-flight runs carrying the quota's tag and
|
|
2692
|
+
* throws {@link ConcurrencyLimitError} once they reach the limit.
|
|
2693
|
+
*
|
|
2694
|
+
* A SOFT cap under a race: the count and the run's creation are separate statements, so N starts
|
|
2695
|
+
* racing on the last free slot can each see it free (the same guarantee a hand-rolled
|
|
2696
|
+
* `SELECT count(*)` gate gives). It is exact whenever starts for a key are not simultaneous, and the
|
|
2697
|
+
* overshoot is bounded by the number of truly concurrent starts. Use `singleton` when you need a
|
|
2698
|
+
* strict, queueing per-key limit instead of a rejecting one.
|
|
2699
|
+
*/
|
|
2700
|
+
declare function assertConcurrency(store: StateStore, workflow: string, quota: ConcurrencyQuota): Promise<void>;
|
|
2701
|
+
|
|
2493
2702
|
/**
|
|
2494
2703
|
* Back-compat alias of {@link WorkflowCtx}. `localStep` — the checkpointed in-process step primitive
|
|
2495
2704
|
* used for saga compensation — is now part of the public {@link WorkflowCtx}, so this type adds
|
|
@@ -3010,6 +3219,173 @@ type RoutingResolution = RoutableResolution | BlockedResolution;
|
|
|
3010
3219
|
*/
|
|
3011
3220
|
declare function resolveRouting(handler: CapabilityRequirement, workers: readonly (RawWorkerDescriptor | WorkerDescriptor)[]): RoutingResolution;
|
|
3012
3221
|
|
|
3222
|
+
/**
|
|
3223
|
+
* A schedule definition — what `engine.schedules.create/upsert` take. Temporal-style: a persisted,
|
|
3224
|
+
* runtime-managed recurring start of `workflow` with `input`, fired by every driving engine's timer
|
|
3225
|
+
* poll (safe with many workers: each window's run id is deterministic, `start` is idempotent, and
|
|
3226
|
+
* advancing the schedule is a compare-and-set).
|
|
3227
|
+
*/
|
|
3228
|
+
interface ScheduleOptions {
|
|
3229
|
+
/** Stable id, unique per store (e.g. `digest:user-42`). Part of every run id it starts. */
|
|
3230
|
+
id: string;
|
|
3231
|
+
/** The workflow to start — a registered name or `@Workflow` class. */
|
|
3232
|
+
workflow: WorkflowRef;
|
|
3233
|
+
/** The input every run starts with. */
|
|
3234
|
+
input?: unknown;
|
|
3235
|
+
/** Cron expression (5 fields, or 6 with leading seconds). Needs the `cron-parser` peer. */
|
|
3236
|
+
cron?: string | undefined;
|
|
3237
|
+
/** Fixed interval (`'15m'`, or ms), windows aligned to the epoch. Exclusive with `cron`. */
|
|
3238
|
+
every?: string | number | undefined;
|
|
3239
|
+
/** IANA timezone the cron is evaluated in (e.g. `America/Sao_Paulo`). Default UTC. */
|
|
3240
|
+
timezone?: string | undefined;
|
|
3241
|
+
/**
|
|
3242
|
+
* Delay each fire by up to this much (`'30s'` or ms) — a stable per-(schedule, window) offset, so
|
|
3243
|
+
* thousands of schedules on the same cron don't all start in the same second.
|
|
3244
|
+
*/
|
|
3245
|
+
jitter?: string | number | undefined;
|
|
3246
|
+
/**
|
|
3247
|
+
* The previous run of this schedule is still in flight when the next window comes due:
|
|
3248
|
+
* `'allow'` (default) starts the new one anyway; `'skip'` skips that window.
|
|
3249
|
+
*/
|
|
3250
|
+
overlap?: 'allow' | 'skip' | undefined;
|
|
3251
|
+
/**
|
|
3252
|
+
* Windows missed while nothing polled (all schedulers down): `'latest'` (default) fires the most
|
|
3253
|
+
* recent missed window once; `'skip'` drops them and waits for the next window. Never more than one
|
|
3254
|
+
* catch-up run per schedule.
|
|
3255
|
+
*/
|
|
3256
|
+
catchup?: 'latest' | 'skip' | undefined;
|
|
3257
|
+
/** Create paused (never due until `resume`). On `upsert`, omit to keep the current paused state. */
|
|
3258
|
+
paused?: boolean | undefined;
|
|
3259
|
+
/** Free-form note shown with the schedule (why it exists / why it's paused). */
|
|
3260
|
+
note?: string | undefined;
|
|
3261
|
+
/** Namespace of the schedule and of the runs it starts. Defaults to the engine's own namespace. */
|
|
3262
|
+
namespace?: string | undefined;
|
|
3263
|
+
/** Labels to find the schedule by — also stamped on every run it starts (plus `schedule:<id>`). */
|
|
3264
|
+
tags?: string[] | undefined;
|
|
3265
|
+
/** Search attributes stamped on every run it starts. */
|
|
3266
|
+
searchAttributes?: SearchAttributes | undefined;
|
|
3267
|
+
/** Dispatch priority for the runs it starts. */
|
|
3268
|
+
priority?: number | undefined;
|
|
3269
|
+
/**
|
|
3270
|
+
* A start-time concurrency quota applied to every run it starts (see `StartOptions.concurrency`):
|
|
3271
|
+
* a window whose start would exceed it is recorded as the schedule's `lastError` and skipped, and
|
|
3272
|
+
* the schedule moves on to its next window.
|
|
3273
|
+
*/
|
|
3274
|
+
concurrency?: ConcurrencyQuota | undefined;
|
|
3275
|
+
}
|
|
3276
|
+
/** A schedule as `engine.schedules.get/list` describe it. */
|
|
3277
|
+
interface ScheduleDescription {
|
|
3278
|
+
id: string;
|
|
3279
|
+
workflow: string;
|
|
3280
|
+
input: unknown;
|
|
3281
|
+
namespace: string;
|
|
3282
|
+
cron?: string | undefined;
|
|
3283
|
+
everyMs?: number | undefined;
|
|
3284
|
+
timezone?: string | undefined;
|
|
3285
|
+
jitterMs?: number | undefined;
|
|
3286
|
+
overlap: 'allow' | 'skip';
|
|
3287
|
+
catchup: 'latest' | 'skip';
|
|
3288
|
+
paused: boolean;
|
|
3289
|
+
note?: string | undefined;
|
|
3290
|
+
tags?: string[] | undefined;
|
|
3291
|
+
searchAttributes?: SearchAttributes | undefined;
|
|
3292
|
+
priority?: number | undefined;
|
|
3293
|
+
concurrency?: ConcurrencyQuota | undefined;
|
|
3294
|
+
/** When it is next due (jitter included), or null if it never fires again / paused. */
|
|
3295
|
+
nextFireAt: Date | null;
|
|
3296
|
+
/** The last window it fired for, and the run that window started. */
|
|
3297
|
+
lastFireAt?: Date | undefined;
|
|
3298
|
+
lastRunId?: string | undefined;
|
|
3299
|
+
/** How many windows it has fired (manual triggers excluded). */
|
|
3300
|
+
fires: number;
|
|
3301
|
+
/** The last start failure (e.g. a concurrency limit), cleared by the next successful start. */
|
|
3302
|
+
lastError?: string | undefined;
|
|
3303
|
+
createdAt: Date;
|
|
3304
|
+
updatedAt: Date;
|
|
3305
|
+
}
|
|
3306
|
+
/** Filter for `engine.schedules.list`. */
|
|
3307
|
+
type ScheduleListQuery = Omit<ScheduleQuery, 'dueBy'>;
|
|
3308
|
+
/** Thrown by `engine.schedules.create` when the id is taken (use `upsert` to replace). */
|
|
3309
|
+
declare class ScheduleAlreadyExistsError extends Error {
|
|
3310
|
+
readonly scheduleId: string;
|
|
3311
|
+
constructor(scheduleId: string);
|
|
3312
|
+
}
|
|
3313
|
+
/** Thrown by `engine.schedules.*` on an id that doesn't exist. */
|
|
3314
|
+
declare class ScheduleNotFoundError extends Error {
|
|
3315
|
+
readonly scheduleId: string;
|
|
3316
|
+
constructor(scheduleId: string);
|
|
3317
|
+
}
|
|
3318
|
+
/** The engine surface the schedule client drives. */
|
|
3319
|
+
interface ScheduleHost {
|
|
3320
|
+
start(workflow: string, input: unknown, runId: string, opts?: StartOptions): Promise<RunResult>;
|
|
3321
|
+
getRun(runId: string): Promise<WorkflowRun | null>;
|
|
3322
|
+
}
|
|
3323
|
+
/** Engine-level knobs for the client. */
|
|
3324
|
+
interface ScheduleClientOptions {
|
|
3325
|
+
/** The engine's namespace: the default for new schedules, and which ones `tick` fires. */
|
|
3326
|
+
namespace?: string | undefined;
|
|
3327
|
+
clock?: (() => number) | undefined;
|
|
3328
|
+
}
|
|
3329
|
+
/**
|
|
3330
|
+
* Persisted, runtime-managed schedules — `engine.schedules`. Unlike the code-registered
|
|
3331
|
+
* `schedules` module option, these live in the store: create/update/pause/delete them at runtime
|
|
3332
|
+
* (one per user, per tenant, per automation…), and every driving engine's timer poll fires the due
|
|
3333
|
+
* ones via {@link tick}.
|
|
3334
|
+
*
|
|
3335
|
+
* Multi-worker safety comes from two properties, not from a lock: a window's run id is deterministic
|
|
3336
|
+
* (`sched:<id>:<windowMs>`), so racing starts of the same window collapse into one run; and a
|
|
3337
|
+
* schedule is advanced with a compare-and-set on its `nextFireAt`, so exactly one poller moves it on.
|
|
3338
|
+
* A crash between starting the run and advancing the schedule just re-fires the (idempotent) start.
|
|
3339
|
+
*/
|
|
3340
|
+
declare class ScheduleClient {
|
|
3341
|
+
private readonly store;
|
|
3342
|
+
private readonly host;
|
|
3343
|
+
private readonly options;
|
|
3344
|
+
constructor(store: StateStore, host: ScheduleHost, options?: ScheduleClientOptions);
|
|
3345
|
+
private now;
|
|
3346
|
+
/** Whether the store persists schedules (implements the schedule methods). */
|
|
3347
|
+
get supported(): boolean;
|
|
3348
|
+
private requireStore;
|
|
3349
|
+
/** Create a schedule. Throws {@link ScheduleAlreadyExistsError} if the id is taken. */
|
|
3350
|
+
create(opts: ScheduleOptions): Promise<ScheduleDescription>;
|
|
3351
|
+
/**
|
|
3352
|
+
* Create the schedule, or replace the definition of an existing one (its history — last fire, last
|
|
3353
|
+
* run, fire count — is kept). The next fire is recomputed from now under the new definition, so a
|
|
3354
|
+
* window that already fired is never fired again by an upsert.
|
|
3355
|
+
*/
|
|
3356
|
+
upsert(opts: ScheduleOptions): Promise<ScheduleDescription>;
|
|
3357
|
+
/** The schedule `id`, or null. */
|
|
3358
|
+
get(id: string): Promise<ScheduleDescription | null>;
|
|
3359
|
+
/** Schedules matching `query`, soonest-due first. */
|
|
3360
|
+
list(query?: ScheduleListQuery): Promise<ScheduleDescription[]>;
|
|
3361
|
+
/** Delete the schedule. Runs it already started are left alone. Returns whether it existed. */
|
|
3362
|
+
delete(id: string): Promise<boolean>;
|
|
3363
|
+
/** Stop firing until {@link resume}. `note` records why (shown by `get`/`list`). */
|
|
3364
|
+
pause(id: string, note?: string): Promise<ScheduleDescription>;
|
|
3365
|
+
/**
|
|
3366
|
+
* Fire again from the next window after now — the windows skipped while paused are NOT caught up.
|
|
3367
|
+
*/
|
|
3368
|
+
resume(id: string): Promise<ScheduleDescription>;
|
|
3369
|
+
/**
|
|
3370
|
+
* Start one run of the schedule right now, outside its cadence (paused or not). The run id is
|
|
3371
|
+
* `sched:<id>:manual:<nowMs>`; it doesn't move the schedule's next fire.
|
|
3372
|
+
*/
|
|
3373
|
+
trigger(id: string): Promise<RunResult>;
|
|
3374
|
+
/**
|
|
3375
|
+
* Fire every due schedule (in this engine's namespace; all namespaces for an operator engine):
|
|
3376
|
+
* start its window's run and advance it to the next window. Called by the NestJS timer poller on
|
|
3377
|
+
* each tick when `persistedSchedules` is on; call it yourself from any other driver. Returns the
|
|
3378
|
+
* run ids started (or re-found, for an idempotent re-fire).
|
|
3379
|
+
*/
|
|
3380
|
+
tick(nowMs?: number): Promise<string[]>;
|
|
3381
|
+
/** Fire one due schedule and advance it. Returns the run id started, if any. */
|
|
3382
|
+
private fire;
|
|
3383
|
+
/** `overlap: 'skip'` and the previous run of this schedule is still in flight. */
|
|
3384
|
+
private overlapping;
|
|
3385
|
+
private mustGet;
|
|
3386
|
+
private write;
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3013
3389
|
type WorkflowFn = (ctx: InternalWorkflowCtx, input: unknown) => Promise<unknown>;
|
|
3014
3390
|
/**
|
|
3015
3391
|
* Options for {@link WorkflowEngine.start}.
|
|
@@ -3055,6 +3431,12 @@ interface StartOptions {
|
|
|
3055
3431
|
* maps here), so one DB-less-tenant-facing engine can create runs across many namespaces.
|
|
3056
3432
|
*/
|
|
3057
3433
|
namespace?: string | undefined;
|
|
3434
|
+
/**
|
|
3435
|
+
* A start-time concurrency quota for this start — at most `limit` runs sharing `key` in flight;
|
|
3436
|
+
* over it, `start` throws {@link ConcurrencyLimitError} and creates nothing. Overrides the
|
|
3437
|
+
* workflow's registered `concurrency`. See {@link ConcurrencyQuota}.
|
|
3438
|
+
*/
|
|
3439
|
+
concurrency?: ConcurrencyQuota | undefined;
|
|
3058
3440
|
}
|
|
3059
3441
|
/**
|
|
3060
3442
|
* Serialize runs of a workflow that share a key — a durable, FIFO mutex (e.g. one pipeline per base).
|
|
@@ -3305,6 +3687,12 @@ declare class WorkflowEngine {
|
|
|
3305
3687
|
private readonly runDispatcher;
|
|
3306
3688
|
/** Per-key serialization for singleton workflows (admission, back-pressure, notify-on-release). */
|
|
3307
3689
|
private readonly singletons;
|
|
3690
|
+
/**
|
|
3691
|
+
* Persisted, runtime-managed schedules: create/upsert/pause/resume/delete/list/trigger them, and
|
|
3692
|
+
* `tick()` fires the due ones (the NestJS timer poller does it when `persistedSchedules` is on).
|
|
3693
|
+
* Needs a store that persists schedules — every bundled adapter does. See {@link ScheduleClient}.
|
|
3694
|
+
*/
|
|
3695
|
+
readonly schedules: ScheduleClient;
|
|
3308
3696
|
/** Every registered workflow, keyed by `name@version` — so old versions stay runnable. */
|
|
3309
3697
|
private readonly workflows;
|
|
3310
3698
|
/** The newest registered version per workflow name — used to `start` new runs. */
|
|
@@ -3380,6 +3768,8 @@ declare class WorkflowEngine {
|
|
|
3380
3768
|
register(name: string, version: string, fn: WorkflowFn, opts?: {
|
|
3381
3769
|
tags?: string[] | undefined;
|
|
3382
3770
|
singleton?: SingletonConfig | undefined;
|
|
3771
|
+
/** Start-time concurrency quota — see {@link ConcurrencyConfig}. */
|
|
3772
|
+
concurrency?: ConcurrencyConfig | undefined;
|
|
3383
3773
|
executionTimeout?: string | number | undefined;
|
|
3384
3774
|
validateInput?: ((input: unknown) => void | Promise<void>) | undefined;
|
|
3385
3775
|
/** Typed/validated `searchAttributes` shape — see `RegisteredWorkflow.searchAttributesSchema`. */
|
|
@@ -3426,6 +3816,7 @@ declare class WorkflowEngine {
|
|
|
3426
3816
|
executor: WorkflowExecutor;
|
|
3427
3817
|
tags?: string[];
|
|
3428
3818
|
singleton?: SingletonConfig;
|
|
3819
|
+
concurrency?: ConcurrencyConfig;
|
|
3429
3820
|
executionTimeout?: string | number;
|
|
3430
3821
|
validateInput?: (input: unknown) => void | Promise<void>;
|
|
3431
3822
|
/** Capabilities a live worker must advertise to run this remote workflow's turns (handshake §7.5). */
|
|
@@ -3451,6 +3842,7 @@ declare class WorkflowEngine {
|
|
|
3451
3842
|
version?: string;
|
|
3452
3843
|
tags?: string[];
|
|
3453
3844
|
singleton?: SingletonConfig;
|
|
3845
|
+
concurrency?: ConcurrencyConfig;
|
|
3454
3846
|
executionTimeout?: string | number;
|
|
3455
3847
|
validateInput?: (input: unknown) => void | Promise<void>;
|
|
3456
3848
|
/** Capabilities a live worker must advertise to run this workflow's turns (handshake §7.5). */
|
|
@@ -3504,7 +3896,23 @@ declare class WorkflowEngine {
|
|
|
3504
3896
|
start<TInput>(workflow: string, input: TInput, runId: string, opts?: StartOptions): Promise<RunResult>;
|
|
3505
3897
|
/** Read a run's current persisted state (or null if unknown). A thin pass-through to the store. */
|
|
3506
3898
|
getRun(runId: string): Promise<WorkflowRun | null>;
|
|
3899
|
+
/**
|
|
3900
|
+
* Re-execute a run's body (replaying its checkpoints). This is the EXPLICIT entry point: besides
|
|
3901
|
+
* driving a live run, it re-drives a `failed` run — the manual retry (prefer {@link requeue}, which
|
|
3902
|
+
* also resets the failure state so replay re-attempts the failed parts). Completed / cancelled /
|
|
3903
|
+
* dead runs are never re-executed. The engine's own implicit wake-ups (signals, step results,
|
|
3904
|
+
* timers, redelivered dispatches) go through {@link resumeImplicit}, which treats `failed` as
|
|
3905
|
+
* terminal too.
|
|
3906
|
+
*/
|
|
3507
3907
|
resume(runId: string): Promise<RunResult>;
|
|
3908
|
+
/**
|
|
3909
|
+
* {@link resume} for every IMPLICIT wake-up — a delivered signal/child completion, a late step
|
|
3910
|
+
* result, a due timer, a redelivered dispatch, a queue-slot wake. A `failed` run is terminal to
|
|
3911
|
+
* these: only an explicit retry ({@link requeue} / {@link resume}) may re-drive it. Otherwise a
|
|
3912
|
+
* stale waiter or a late result left behind by a failed run silently re-executes its body.
|
|
3913
|
+
*/
|
|
3914
|
+
private resumeImplicit;
|
|
3915
|
+
private resumeRun;
|
|
3508
3916
|
/**
|
|
3509
3917
|
* The registration for an UNREGISTERED run, INHERITED from its nearest REMOTE ancestor — or
|
|
3510
3918
|
* `undefined` if it has none (the skew-protection error case in {@link resume}). Callers check the
|
|
@@ -3878,6 +4286,43 @@ declare class WorkflowEngine {
|
|
|
3878
4286
|
* its worker (its next checkpoint write fails). Returns the number of runs deleted (0 if absent).
|
|
3879
4287
|
*/
|
|
3880
4288
|
deleteRun(runId: string): Promise<number>;
|
|
4289
|
+
/**
|
|
4290
|
+
* Hard-delete EVERY run matching `scope` — plus, by default, each one's whole child subtree — in
|
|
4291
|
+
* bounded batches. The "forget this tenant" / "drop this feature's history" operation: where
|
|
4292
|
+
* {@link deleteRun} removes one tree you already know the id of, this drains everything a scope
|
|
4293
|
+
* selects (`{ namespace: 'acme' }`, `{ tag: 'tenant:acme' }`, `{ workflows: [...] }`, attribute
|
|
4294
|
+
* predicates …) through the store API, so no caller has to reach into the `durable_*` tables.
|
|
4295
|
+
*
|
|
4296
|
+
* - **Live runs** (not yet terminal) are {@link cancel cancelled} first (plain cancel, no saga
|
|
4297
|
+
* undo), which tells any worker holding one to stop, and then deleted with the rest. Pass
|
|
4298
|
+
* `cancelLive: false` to leave live runs (and live descendants of finished ones) alone and
|
|
4299
|
+
* delete terminal history only.
|
|
4300
|
+
* - **Children** are found through the same parent→child edges as {@link getRunChildren} and deleted
|
|
4301
|
+
* with their root even when they don't match `scope` themselves (children inherit `namespace`,
|
|
4302
|
+
* but not `tags`). `children: false` deletes exactly the matching runs.
|
|
4303
|
+
* - **Batched**: `batchSize` runs (default 500) per round, each round one bulk
|
|
4304
|
+
* {@link StateStore.deleteRuns} (falling back to per-run {@link StateStore.deleteRun}).
|
|
4305
|
+
*
|
|
4306
|
+
* An EMPTY scope is rejected — it would delete every run in the store. Returns how many runs were
|
|
4307
|
+
* deleted (children included).
|
|
4308
|
+
*/
|
|
4309
|
+
purgeRuns(scope: RunScope, opts?: {
|
|
4310
|
+
batchSize?: number;
|
|
4311
|
+
cancelLive?: boolean;
|
|
4312
|
+
children?: boolean;
|
|
4313
|
+
}): Promise<number>;
|
|
4314
|
+
/**
|
|
4315
|
+
* {@link purgeRuns} for one namespace — every run (and child) a tenant/partition owns. Children
|
|
4316
|
+
* inherit their parent's namespace, so a namespace purge is complete by construction.
|
|
4317
|
+
*/
|
|
4318
|
+
purgeNamespace(namespace: string, opts?: {
|
|
4319
|
+
batchSize?: number;
|
|
4320
|
+
cancelLive?: boolean;
|
|
4321
|
+
}): Promise<number>;
|
|
4322
|
+
/** The given runs plus every descendant, children before parents. One waiter scan for the batch. */
|
|
4323
|
+
private collectSubtrees;
|
|
4324
|
+
/** Bulk-delete through the store's `deleteRuns`, or one `deleteRun` per id when it has none. */
|
|
4325
|
+
private deleteRunIds;
|
|
3881
4326
|
/**
|
|
3882
4327
|
* Cascade cancellation to a run's children — both awaited (`ctx.child`, found via its live
|
|
3883
4328
|
* `child:<id>` waiter) and fire-and-forget (`ctx.startChild`, found via its `spawn:<id>`
|
|
@@ -4400,6 +4845,19 @@ declare class FatalError extends Error {
|
|
|
4400
4845
|
readonly code?: string | undefined;
|
|
4401
4846
|
constructor(message: string, code?: string);
|
|
4402
4847
|
}
|
|
4848
|
+
/**
|
|
4849
|
+
* Thrown by `start` when a run would exceed its concurrency quota: `active` runs sharing the quota
|
|
4850
|
+
* `key` are already in flight (in the quota's counted statuses) and the `limit` is `limit`. Nothing
|
|
4851
|
+
* was created — the start is rejected up front, so the caller can shed load or answer "try again in a
|
|
4852
|
+
* moment" (e.g. map it to HTTP 429). See `StartOptions.concurrency` / `ConcurrencyConfig`.
|
|
4853
|
+
*/
|
|
4854
|
+
declare class ConcurrencyLimitError extends Error {
|
|
4855
|
+
readonly workflow: string;
|
|
4856
|
+
readonly key: string;
|
|
4857
|
+
readonly limit: number;
|
|
4858
|
+
readonly active: number;
|
|
4859
|
+
constructor(workflow: string, key: string, limit: number, active: number);
|
|
4860
|
+
}
|
|
4403
4861
|
/**
|
|
4404
4862
|
* Thrown by `start` when a singleton workflow's wait queue is full: the count of in-flight + gated
|
|
4405
4863
|
* runs sharing the key already equals `limit + maxQueueDepth`, so admitting another would let the
|
|
@@ -4467,6 +4925,26 @@ declare class NonDeterminismError extends Error {
|
|
|
4467
4925
|
readonly seq: number;
|
|
4468
4926
|
constructor(runId: string, seq: number, expected: string, recorded: string);
|
|
4469
4927
|
}
|
|
4928
|
+
/**
|
|
4929
|
+
* Thrown AT THE CALL SITE when a workflow-ctx primitive (`ctx.startChild`, `ctx.child`, `ctx.step`,
|
|
4930
|
+
* `ctx.sleep`, `ctx.sideEffect`, … — or a `MyWorkflow.start()`/`.execute()` static, which route to
|
|
4931
|
+
* them through the ambient ctx) is called from INSIDE the body of a checkpointed step
|
|
4932
|
+
* (`ctx.localStep`, `ctx.transaction`, `ctx.sideEffect`, `ctx.now`, `ctx.task`'s dispatch).
|
|
4933
|
+
*
|
|
4934
|
+
* A step body runs once and is replayed from its checkpoint WITHOUT re-running, so a primitive it
|
|
4935
|
+
* called claims a journal position on the first run that no replay ever claims again: every later
|
|
4936
|
+
* position shifts and the run dies on its next replay with a `NonDeterminismError` far from the
|
|
4937
|
+
* cause. Failing here instead names the real mistake. Move the call out of the step body (into the
|
|
4938
|
+
* workflow body), or — from a dispatched `@Step` handler — start a top-level run.
|
|
4939
|
+
*
|
|
4940
|
+
* A `FatalError` (code `nested_workflow_call`): the step is not retried, the run fails.
|
|
4941
|
+
*/
|
|
4942
|
+
declare class NestedWorkflowCallError extends FatalError {
|
|
4943
|
+
readonly runId: string;
|
|
4944
|
+
readonly primitive: string;
|
|
4945
|
+
readonly step: string;
|
|
4946
|
+
constructor(runId: string, primitive: string, step: string);
|
|
4947
|
+
}
|
|
4470
4948
|
/**
|
|
4471
4949
|
* Thrown by `ctx.all` when one or more parallel child workflows fail. Carries the per-item failures
|
|
4472
4950
|
* (input index, child run id, error message) and presents an aggregate message summarizing the count
|
|
@@ -4660,7 +5138,7 @@ declare const RUN_VALUE_FACET_SCAN = 5000;
|
|
|
4660
5138
|
* sets exactly that), so it stays offered — just after the tags a human wrote. `version:undeclared`
|
|
4661
5139
|
* is engine-minted too but is a single fixed value, so it competes fairly and is not listed here.
|
|
4662
5140
|
*/
|
|
4663
|
-
declare const ENGINE_MINTED_TAG_PREFIXES: readonly ["singleton:"];
|
|
5141
|
+
declare const ENGINE_MINTED_TAG_PREFIXES: readonly ["singleton:", "concurrency:"];
|
|
4664
5142
|
/** Is this a tag the engine mints one of per key? See {@link ENGINE_MINTED_TAG_PREFIXES}. */
|
|
4665
5143
|
declare function isEngineMintedTag(value: string | null): boolean;
|
|
4666
5144
|
/**
|
|
@@ -4863,6 +5341,22 @@ declare class CodecStateStore implements StateStore {
|
|
|
4863
5341
|
* Bound the same conditional way as {@link runFacets} so absence is reported, not faked.
|
|
4864
5342
|
*/
|
|
4865
5343
|
readonly runValueFacets?: (axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions) => Promise<RunValueFacetRow[]>;
|
|
5344
|
+
/** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
|
|
5345
|
+
* engine's per-run fallback still kicks in through the wrapper. */
|
|
5346
|
+
readonly deleteRuns?: (runIds: string[]) => Promise<void>;
|
|
5347
|
+
/** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
|
|
5348
|
+
* when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
|
|
5349
|
+
readonly pruneTerminalRuns?: (policy: RetentionPolicy, nowMs: number, limit: number) => Promise<number>;
|
|
5350
|
+
/** Forwarded verbatim — a count reads no payload. Bound only when the inner store counts, so the
|
|
5351
|
+
* engine's facet/listing fallback still applies through the wrapper. */
|
|
5352
|
+
readonly countRuns?: (query: Omit<RunQuery, 'limit' | 'offset'>) => Promise<number>;
|
|
5353
|
+
/** Schedules persist their run `input` inside `spec` — encoded like any other payload. Bound only
|
|
5354
|
+
* when the inner store persists schedules, so `engine.schedules` reports absence faithfully. */
|
|
5355
|
+
readonly saveSchedule?: (record: ScheduleRecord) => Promise<void>;
|
|
5356
|
+
readonly getSchedule?: (id: string) => Promise<ScheduleRecord | null>;
|
|
5357
|
+
readonly updateSchedule?: (id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null) => Promise<boolean>;
|
|
5358
|
+
readonly deleteSchedule?: (id: string) => Promise<boolean>;
|
|
5359
|
+
readonly listSchedules?: (query: ScheduleQuery) => Promise<ScheduleRecord[]>;
|
|
4866
5360
|
constructor(inner: StateStore, codec: PayloadCodec);
|
|
4867
5361
|
private enc;
|
|
4868
5362
|
private dec;
|
|
@@ -4870,6 +5364,9 @@ declare class CodecStateStore implements StateStore {
|
|
|
4870
5364
|
private decRun;
|
|
4871
5365
|
private encCp;
|
|
4872
5366
|
private decCp;
|
|
5367
|
+
private encSpec;
|
|
5368
|
+
private encSchedule;
|
|
5369
|
+
private decSchedule;
|
|
4873
5370
|
ensureSchema(): Promise<void>;
|
|
4874
5371
|
createRun(run: WorkflowRun): Promise<void>;
|
|
4875
5372
|
updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void>;
|
|
@@ -5039,6 +5536,12 @@ declare function scheduledRunId(key: string, everyMs: number, nowMs: number): st
|
|
|
5039
5536
|
* interval resolves to the same fire time — and thus the same idempotent run id.
|
|
5040
5537
|
*/
|
|
5041
5538
|
declare function prevCronFireMs(expr: string, nowMs: number, timezone?: string): number;
|
|
5539
|
+
/**
|
|
5540
|
+
* Epoch ms of the first cron fire STRICTLY after `afterMs`, evaluated in `timezone` (default UTC) —
|
|
5541
|
+
* the forward counterpart of {@link prevCronFireMs}, used by persisted schedules to compute when a
|
|
5542
|
+
* schedule is next due.
|
|
5543
|
+
*/
|
|
5544
|
+
declare function nextCronFireMs(expr: string, afterMs: number, timezone?: string): number;
|
|
5042
5545
|
/**
|
|
5043
5546
|
* Start each schedule's current-window run. The run id is the time bucket (a fixed-interval index,
|
|
5044
5547
|
* or the cron fire time) and `engine.start` is idempotent, so firing this on an interval — or
|
|
@@ -5297,6 +5800,8 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
5297
5800
|
updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void>;
|
|
5298
5801
|
getRun(runId: string): Promise<WorkflowRun | null>;
|
|
5299
5802
|
deleteRun(runId: string): Promise<void>;
|
|
5803
|
+
deleteRuns(runIds: string[]): Promise<void>;
|
|
5804
|
+
pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
|
|
5300
5805
|
getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
|
|
5301
5806
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
5302
5807
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
@@ -5343,11 +5848,18 @@ declare class InMemoryStateStore implements StateStore {
|
|
|
5343
5848
|
* {@link listRuns} (which then sorts + pages it) and {@link runFacets} (which groups it). */
|
|
5344
5849
|
private matching;
|
|
5345
5850
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
5851
|
+
countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
|
|
5346
5852
|
runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
5347
5853
|
/** Counted over the newest `scan` matching runs for EVERY axis, not just `tag`: this store holds
|
|
5348
5854
|
* its runs in a Map with no index to group by, so the bound that the SQL stores need only for tags
|
|
5349
5855
|
* is the honest one to apply here throughout. */
|
|
5350
5856
|
runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
|
|
5857
|
+
private readonly schedules;
|
|
5858
|
+
saveSchedule(record: ScheduleRecord): Promise<void>;
|
|
5859
|
+
getSchedule(id: string): Promise<ScheduleRecord | null>;
|
|
5860
|
+
updateSchedule(id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null): Promise<boolean>;
|
|
5861
|
+
deleteSchedule(id: string): Promise<boolean>;
|
|
5862
|
+
listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]>;
|
|
5351
5863
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
5352
5864
|
getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
|
|
5353
5865
|
listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
|
|
@@ -5379,4 +5891,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
|
|
|
5379
5891
|
onControl(handler: (msg: ControlMessage) => void): void;
|
|
5380
5892
|
}
|
|
5381
5893
|
|
|
5382
|
-
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, 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, 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, FatalError, GatherError, type GroupHealth, 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, NonDeterminismError, 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 RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScalarAttributeFilter, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, 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 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, announcementsOf, applyAttributeQuery, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, collectMetrics, controlPlaneDescriptor, coveredTokens, createStepLogger, currentStep, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isLegacyDescriptor, isWorkflowControlFlowSignal, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
|
|
5894
|
+
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, 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, FatalError, GatherError, type GroupHealth, 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 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 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, STATE_STORE, STATE_STORE_CANONICAL, 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, 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, announcementsOf, applyAttributeQuery, assertConcurrency, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
|