@dudousxd/nestjs-durable-core 0.49.1 → 0.49.3
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 +65 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -2
- package/dist/index.d.ts +76 -2
- package/dist/index.js +61 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -330,6 +330,27 @@ interface WorkflowRun {
|
|
|
330
330
|
createdAt: Date;
|
|
331
331
|
updatedAt: Date;
|
|
332
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* WHAT an event-parked suspended run is waiting on, resolved for display — the engine keeps one
|
|
335
|
+
* generic `suspended` status (it's what drives recovery/timers/queries), but to a human "waiting on
|
|
336
|
+
* signal `approve`" reads very differently from "waiting on webhook `stripe-cb`". Computed by the
|
|
337
|
+
* store-backed gateway from the run's signal waiters (`listSignalWaiters`, ONE bulk scan), so the
|
|
338
|
+
* dashboard can NAME the wait in a list row without fetching each run's timeline. `on` is derived from
|
|
339
|
+
* the waiter token's prefix (see `classifyWaiterToken`): `wh:<runId>:<seq>` ⇒ `webhook`, `child:<id>`
|
|
340
|
+
* ⇒ `child`, `event:<name>:…` ⇒ `signal` (name decoded), anything else ⇒ `signal` (the token IS the
|
|
341
|
+
* signal name).
|
|
342
|
+
*
|
|
343
|
+
* Deliberately EVENT-only (no timer/step): `wakeAt` alone can't tell a real `ctx.sleep` from the
|
|
344
|
+
* reconcile-fallback `wakeAt` an event/step suspend now carries, and the store exposes no cheap bulk
|
|
345
|
+
* checkpoint scan to disambiguate — so the client shows a non-event suspend with a live worker as
|
|
346
|
+
* `running` (it flips off "no worker" the moment a worker returns) rather than guessing "sleeping".
|
|
347
|
+
* The detail view (which has the timeline) still distinguishes sleep vs in-flight step precisely.
|
|
348
|
+
*/
|
|
349
|
+
interface RunWaiting {
|
|
350
|
+
on: 'signal' | 'webhook' | 'child';
|
|
351
|
+
/** The token/name the run is parked on — the signal name, webhook token, or awaited child id. */
|
|
352
|
+
name: string;
|
|
353
|
+
}
|
|
333
354
|
type StepKind = 'local' | 'remote' | 'sleep' | 'signal';
|
|
334
355
|
/**
|
|
335
356
|
* The recorded result of a single step at a deterministic logical position (`seq`).
|
|
@@ -1784,6 +1805,19 @@ interface WorkflowEngineDeps {
|
|
|
1784
1805
|
* one (this rearmed window for heartbeat-aware workers, or the fixed `timeoutMs` otherwise).
|
|
1785
1806
|
*/
|
|
1786
1807
|
remoteAdvanceSilenceMs?: number | undefined;
|
|
1808
|
+
/**
|
|
1809
|
+
* Fallback re-drive window (ms) for a run that SUSPENDS with no natural timer — i.e. it's waiting on
|
|
1810
|
+
* an EVENT to wake it (a child's completion, a signal, a remote step with no `timeoutMs`) rather than
|
|
1811
|
+
* a `ctx.sleep`. Those events re-drive the run directly; but if the wake is LOST (the delivering pod
|
|
1812
|
+
* crashed / rolled mid-handoff), the run would otherwise sit `suspended` forever with `wakeAt: null` —
|
|
1813
|
+
* invisible to both the timer poller (no `wakeAt`) and crash-recovery (no lease). This stamps a
|
|
1814
|
+
* fallback `wakeAt` so {@link resumeDueTimers} re-drives it after the window; the re-drive is an
|
|
1815
|
+
* idempotent replay (a still-pending dependency re-suspends via the checkpoint guard, a settled one
|
|
1816
|
+
* advances), so it's a safe self-heal, not a retry that can double-dispatch. The primary event path
|
|
1817
|
+
* still wins first for a healthy run (it re-drives long before this fires), so this only ever fires
|
|
1818
|
+
* for a genuinely-orphaned run. Default 5min; set `0` to disable (the prior wake-forever behavior).
|
|
1819
|
+
*/
|
|
1820
|
+
reconcileMs?: number | undefined;
|
|
1787
1821
|
/**
|
|
1788
1822
|
* Build the public callback URL for a `ctx.webhook()` token (e.g.
|
|
1789
1823
|
* ``(t) => `https://api.example.com/durable/webhooks/${t}` ``). Populates
|
|
@@ -1859,6 +1893,7 @@ declare class WorkflowEngine {
|
|
|
1859
1893
|
private readonly leaseMs;
|
|
1860
1894
|
private readonly maxRecoveryAttempts?;
|
|
1861
1895
|
private readonly remoteAdvanceSilenceMs?;
|
|
1896
|
+
private readonly reconcileMs;
|
|
1862
1897
|
private readonly webhookUrl?;
|
|
1863
1898
|
private readonly traceparent?;
|
|
1864
1899
|
private readonly context?;
|
|
@@ -2324,6 +2359,13 @@ declare class WorkflowEngine {
|
|
|
2324
2359
|
* keeps its own lease handling (the TS executor's `finally`, the remote path's caller).
|
|
2325
2360
|
*/
|
|
2326
2361
|
private settleRun;
|
|
2362
|
+
/**
|
|
2363
|
+
* A wakeAt to persist on a suspend: the natural timer if the turn produced one (a `ctx.sleep`, a
|
|
2364
|
+
* remote-step deadline), else the {@link reconcileMs} fallback so an event-waiting run (child/signal/
|
|
2365
|
+
* timeout-less remote step) can't be orphaned forever if its wake is lost. `undefined` only when the
|
|
2366
|
+
* fallback is disabled (`reconcileMs: 0`). See {@link WorkflowEngineDeps.reconcileMs}.
|
|
2367
|
+
*/
|
|
2368
|
+
private reconcileWakeAt;
|
|
2327
2369
|
private runRemoteExecution;
|
|
2328
2370
|
/**
|
|
2329
2371
|
* Apply a remote workflow turn's {@link WorkflowDecision}: persist the local steps it ran, then
|
|
@@ -2732,6 +2774,13 @@ declare class RemoteWorkflowExecutor implements WorkflowExecutor {
|
|
|
2732
2774
|
dispatch(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
2733
2775
|
}
|
|
2734
2776
|
|
|
2777
|
+
/** A run as returned by the gateway's list — the durable run plus an optional {@link RunWaiting}
|
|
2778
|
+
* descriptor the control plane resolves (what a suspended run is parked on), so the dashboard can
|
|
2779
|
+
* name the wait in a list row without fetching each run's timeline. Additive: `waiting` is absent
|
|
2780
|
+
* on a non-parked run and on gateways/versions that don't compute it. */
|
|
2781
|
+
type RunListItem = WorkflowRun & {
|
|
2782
|
+
waiting?: RunWaiting | undefined;
|
|
2783
|
+
};
|
|
2735
2784
|
/** Which durable topology a gateway speaks for — surfaced in the dashboard so an operator can tell a
|
|
2736
2785
|
* control plane from a tenant at a glance (the store-backed gateway is the operator; the proxy is a
|
|
2737
2786
|
* tenant). Cheap, synchronous, local knowledge — no round-trip. */
|
|
@@ -2759,7 +2808,10 @@ interface RunGateway {
|
|
|
2759
2808
|
/** This deployment's durable role (control plane vs tenant) — synchronous local metadata. */
|
|
2760
2809
|
topology(): DurableTopology;
|
|
2761
2810
|
getRunDetail(runId: string): Promise<RunDetail | null>;
|
|
2762
|
-
|
|
2811
|
+
/** List runs, each optionally carrying a {@link RunWaiting} descriptor (what a suspended run is
|
|
2812
|
+
* parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
|
|
2813
|
+
* plane sent. */
|
|
2814
|
+
listRuns(query: RunQuery): Promise<RunListItem[]>;
|
|
2763
2815
|
/** Per-group worker health (queue backlog + live worker heartbeats). On the control plane this is
|
|
2764
2816
|
* every group; over a tenant proxy the operator scopes it to the tenant's own groups. */
|
|
2765
2817
|
workerHealth(): Promise<GroupHealth[]>;
|
|
@@ -2775,6 +2827,25 @@ interface RunGateway {
|
|
|
2775
2827
|
subscribe(runId: string, onEvent: (event: EngineEvent) => void): () => void;
|
|
2776
2828
|
}
|
|
2777
2829
|
|
|
2830
|
+
/**
|
|
2831
|
+
* Resolve WHAT a suspended run is parked on from the token of the {@link SignalWaiter} it registered.
|
|
2832
|
+
* The token prefix carries the kind — no extra store lookup and no new persisted field. Used by the
|
|
2833
|
+
* store-backed run gateway to stamp {@link RunWaiting} onto each listed run so the dashboard can name
|
|
2834
|
+
* the wait in a row without fetching that run's timeline.
|
|
2835
|
+
*/
|
|
2836
|
+
declare function classifyWaiterToken(token: string): RunWaiting;
|
|
2837
|
+
/**
|
|
2838
|
+
* Resolve a suspended run's {@link RunWaiting} from the pending signal waiters (indexed by `runId`).
|
|
2839
|
+
* Event-only by design (see {@link RunWaiting}): a `waitForSignal`/`waitForEvent`/webhook/awaited-child
|
|
2840
|
+
* suspend registers a waiter and gets named here; every other suspend (a bare `ctx.sleep`, an in-flight
|
|
2841
|
+
* remote step, a reconcile-parked orphan) returns `undefined`, so the client layers its own display
|
|
2842
|
+
* state (no-worker, singleton, running) on top — none of which can be told apart from `wakeAt` alone.
|
|
2843
|
+
*/
|
|
2844
|
+
declare function resolveRunWaiting(run: WorkflowRun, waiterByRun: ReadonlyMap<string, SignalWaiter>): RunWaiting | undefined;
|
|
2845
|
+
/** Index signal waiters by `runId`, keeping the first seen per run (a run parks on one waiter at a
|
|
2846
|
+
* time in the sequential case; the earliest is the one it's blocked on). */
|
|
2847
|
+
declare function indexWaitersByRun(waiters: readonly SignalWaiter[]): Map<string, SignalWaiter>;
|
|
2848
|
+
|
|
2778
2849
|
/**
|
|
2779
2850
|
* Transforms a payload value as it crosses the store boundary — e.g. encrypt-at-rest, compress, or
|
|
2780
2851
|
* redact PII. `decode` must be the exact inverse of `encode`. Both are synchronous (use a local
|
|
@@ -2838,6 +2909,9 @@ declare class CodecStateStore implements StateStore {
|
|
|
2838
2909
|
declare function eventPrefix(name: string): string;
|
|
2839
2910
|
/** Build the unique waiter token for one `waitForEvent` call (name + match + run position). */
|
|
2840
2911
|
declare function eventToken(name: string, match: Record<string, unknown> | undefined, runId: string, seq: number): string;
|
|
2912
|
+
/** The event name embedded in an event waiter token (the 2nd `:`-segment is the base64 name), so a
|
|
2913
|
+
* dashboard can show "waiting on event `<name>`" instead of the opaque token. */
|
|
2914
|
+
declare function eventNameOf(token: string): string;
|
|
2841
2915
|
/** The match criteria embedded in an event waiter token (the 3rd `:`-segment is the base64 match). */
|
|
2842
2916
|
declare function eventMatchOf(token: string): Record<string, unknown>;
|
|
2843
2917
|
/** Whether `payload` satisfies a waiter's `match`: every match key deep-equals the payload's value. */
|
|
@@ -3152,4 +3226,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
|
|
|
3152
3226
|
onControl(handler: (msg: ControlMessage) => void): void;
|
|
3153
3227
|
}
|
|
3154
3228
|
|
|
3155
|
-
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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, WORKFLOW_NAME_KEY, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventPrefix, eventToken, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
|
|
3229
|
+
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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, WORKFLOW_NAME_KEY, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, classifyWaiterToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, indexWaitersByRun, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
|
package/dist/index.d.ts
CHANGED
|
@@ -330,6 +330,27 @@ interface WorkflowRun {
|
|
|
330
330
|
createdAt: Date;
|
|
331
331
|
updatedAt: Date;
|
|
332
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* WHAT an event-parked suspended run is waiting on, resolved for display — the engine keeps one
|
|
335
|
+
* generic `suspended` status (it's what drives recovery/timers/queries), but to a human "waiting on
|
|
336
|
+
* signal `approve`" reads very differently from "waiting on webhook `stripe-cb`". Computed by the
|
|
337
|
+
* store-backed gateway from the run's signal waiters (`listSignalWaiters`, ONE bulk scan), so the
|
|
338
|
+
* dashboard can NAME the wait in a list row without fetching each run's timeline. `on` is derived from
|
|
339
|
+
* the waiter token's prefix (see `classifyWaiterToken`): `wh:<runId>:<seq>` ⇒ `webhook`, `child:<id>`
|
|
340
|
+
* ⇒ `child`, `event:<name>:…` ⇒ `signal` (name decoded), anything else ⇒ `signal` (the token IS the
|
|
341
|
+
* signal name).
|
|
342
|
+
*
|
|
343
|
+
* Deliberately EVENT-only (no timer/step): `wakeAt` alone can't tell a real `ctx.sleep` from the
|
|
344
|
+
* reconcile-fallback `wakeAt` an event/step suspend now carries, and the store exposes no cheap bulk
|
|
345
|
+
* checkpoint scan to disambiguate — so the client shows a non-event suspend with a live worker as
|
|
346
|
+
* `running` (it flips off "no worker" the moment a worker returns) rather than guessing "sleeping".
|
|
347
|
+
* The detail view (which has the timeline) still distinguishes sleep vs in-flight step precisely.
|
|
348
|
+
*/
|
|
349
|
+
interface RunWaiting {
|
|
350
|
+
on: 'signal' | 'webhook' | 'child';
|
|
351
|
+
/** The token/name the run is parked on — the signal name, webhook token, or awaited child id. */
|
|
352
|
+
name: string;
|
|
353
|
+
}
|
|
333
354
|
type StepKind = 'local' | 'remote' | 'sleep' | 'signal';
|
|
334
355
|
/**
|
|
335
356
|
* The recorded result of a single step at a deterministic logical position (`seq`).
|
|
@@ -1784,6 +1805,19 @@ interface WorkflowEngineDeps {
|
|
|
1784
1805
|
* one (this rearmed window for heartbeat-aware workers, or the fixed `timeoutMs` otherwise).
|
|
1785
1806
|
*/
|
|
1786
1807
|
remoteAdvanceSilenceMs?: number | undefined;
|
|
1808
|
+
/**
|
|
1809
|
+
* Fallback re-drive window (ms) for a run that SUSPENDS with no natural timer — i.e. it's waiting on
|
|
1810
|
+
* an EVENT to wake it (a child's completion, a signal, a remote step with no `timeoutMs`) rather than
|
|
1811
|
+
* a `ctx.sleep`. Those events re-drive the run directly; but if the wake is LOST (the delivering pod
|
|
1812
|
+
* crashed / rolled mid-handoff), the run would otherwise sit `suspended` forever with `wakeAt: null` —
|
|
1813
|
+
* invisible to both the timer poller (no `wakeAt`) and crash-recovery (no lease). This stamps a
|
|
1814
|
+
* fallback `wakeAt` so {@link resumeDueTimers} re-drives it after the window; the re-drive is an
|
|
1815
|
+
* idempotent replay (a still-pending dependency re-suspends via the checkpoint guard, a settled one
|
|
1816
|
+
* advances), so it's a safe self-heal, not a retry that can double-dispatch. The primary event path
|
|
1817
|
+
* still wins first for a healthy run (it re-drives long before this fires), so this only ever fires
|
|
1818
|
+
* for a genuinely-orphaned run. Default 5min; set `0` to disable (the prior wake-forever behavior).
|
|
1819
|
+
*/
|
|
1820
|
+
reconcileMs?: number | undefined;
|
|
1787
1821
|
/**
|
|
1788
1822
|
* Build the public callback URL for a `ctx.webhook()` token (e.g.
|
|
1789
1823
|
* ``(t) => `https://api.example.com/durable/webhooks/${t}` ``). Populates
|
|
@@ -1859,6 +1893,7 @@ declare class WorkflowEngine {
|
|
|
1859
1893
|
private readonly leaseMs;
|
|
1860
1894
|
private readonly maxRecoveryAttempts?;
|
|
1861
1895
|
private readonly remoteAdvanceSilenceMs?;
|
|
1896
|
+
private readonly reconcileMs;
|
|
1862
1897
|
private readonly webhookUrl?;
|
|
1863
1898
|
private readonly traceparent?;
|
|
1864
1899
|
private readonly context?;
|
|
@@ -2324,6 +2359,13 @@ declare class WorkflowEngine {
|
|
|
2324
2359
|
* keeps its own lease handling (the TS executor's `finally`, the remote path's caller).
|
|
2325
2360
|
*/
|
|
2326
2361
|
private settleRun;
|
|
2362
|
+
/**
|
|
2363
|
+
* A wakeAt to persist on a suspend: the natural timer if the turn produced one (a `ctx.sleep`, a
|
|
2364
|
+
* remote-step deadline), else the {@link reconcileMs} fallback so an event-waiting run (child/signal/
|
|
2365
|
+
* timeout-less remote step) can't be orphaned forever if its wake is lost. `undefined` only when the
|
|
2366
|
+
* fallback is disabled (`reconcileMs: 0`). See {@link WorkflowEngineDeps.reconcileMs}.
|
|
2367
|
+
*/
|
|
2368
|
+
private reconcileWakeAt;
|
|
2327
2369
|
private runRemoteExecution;
|
|
2328
2370
|
/**
|
|
2329
2371
|
* Apply a remote workflow turn's {@link WorkflowDecision}: persist the local steps it ran, then
|
|
@@ -2732,6 +2774,13 @@ declare class RemoteWorkflowExecutor implements WorkflowExecutor {
|
|
|
2732
2774
|
dispatch(run: WorkflowRun, history: HistoryEvent[], taskId: string, pendingSignals?: WorkflowTask['pendingSignals']): Promise<void>;
|
|
2733
2775
|
}
|
|
2734
2776
|
|
|
2777
|
+
/** A run as returned by the gateway's list — the durable run plus an optional {@link RunWaiting}
|
|
2778
|
+
* descriptor the control plane resolves (what a suspended run is parked on), so the dashboard can
|
|
2779
|
+
* name the wait in a list row without fetching each run's timeline. Additive: `waiting` is absent
|
|
2780
|
+
* on a non-parked run and on gateways/versions that don't compute it. */
|
|
2781
|
+
type RunListItem = WorkflowRun & {
|
|
2782
|
+
waiting?: RunWaiting | undefined;
|
|
2783
|
+
};
|
|
2735
2784
|
/** Which durable topology a gateway speaks for — surfaced in the dashboard so an operator can tell a
|
|
2736
2785
|
* control plane from a tenant at a glance (the store-backed gateway is the operator; the proxy is a
|
|
2737
2786
|
* tenant). Cheap, synchronous, local knowledge — no round-trip. */
|
|
@@ -2759,7 +2808,10 @@ interface RunGateway {
|
|
|
2759
2808
|
/** This deployment's durable role (control plane vs tenant) — synchronous local metadata. */
|
|
2760
2809
|
topology(): DurableTopology;
|
|
2761
2810
|
getRunDetail(runId: string): Promise<RunDetail | null>;
|
|
2762
|
-
|
|
2811
|
+
/** List runs, each optionally carrying a {@link RunWaiting} descriptor (what a suspended run is
|
|
2812
|
+
* parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
|
|
2813
|
+
* plane sent. */
|
|
2814
|
+
listRuns(query: RunQuery): Promise<RunListItem[]>;
|
|
2763
2815
|
/** Per-group worker health (queue backlog + live worker heartbeats). On the control plane this is
|
|
2764
2816
|
* every group; over a tenant proxy the operator scopes it to the tenant's own groups. */
|
|
2765
2817
|
workerHealth(): Promise<GroupHealth[]>;
|
|
@@ -2775,6 +2827,25 @@ interface RunGateway {
|
|
|
2775
2827
|
subscribe(runId: string, onEvent: (event: EngineEvent) => void): () => void;
|
|
2776
2828
|
}
|
|
2777
2829
|
|
|
2830
|
+
/**
|
|
2831
|
+
* Resolve WHAT a suspended run is parked on from the token of the {@link SignalWaiter} it registered.
|
|
2832
|
+
* The token prefix carries the kind — no extra store lookup and no new persisted field. Used by the
|
|
2833
|
+
* store-backed run gateway to stamp {@link RunWaiting} onto each listed run so the dashboard can name
|
|
2834
|
+
* the wait in a row without fetching that run's timeline.
|
|
2835
|
+
*/
|
|
2836
|
+
declare function classifyWaiterToken(token: string): RunWaiting;
|
|
2837
|
+
/**
|
|
2838
|
+
* Resolve a suspended run's {@link RunWaiting} from the pending signal waiters (indexed by `runId`).
|
|
2839
|
+
* Event-only by design (see {@link RunWaiting}): a `waitForSignal`/`waitForEvent`/webhook/awaited-child
|
|
2840
|
+
* suspend registers a waiter and gets named here; every other suspend (a bare `ctx.sleep`, an in-flight
|
|
2841
|
+
* remote step, a reconcile-parked orphan) returns `undefined`, so the client layers its own display
|
|
2842
|
+
* state (no-worker, singleton, running) on top — none of which can be told apart from `wakeAt` alone.
|
|
2843
|
+
*/
|
|
2844
|
+
declare function resolveRunWaiting(run: WorkflowRun, waiterByRun: ReadonlyMap<string, SignalWaiter>): RunWaiting | undefined;
|
|
2845
|
+
/** Index signal waiters by `runId`, keeping the first seen per run (a run parks on one waiter at a
|
|
2846
|
+
* time in the sequential case; the earliest is the one it's blocked on). */
|
|
2847
|
+
declare function indexWaitersByRun(waiters: readonly SignalWaiter[]): Map<string, SignalWaiter>;
|
|
2848
|
+
|
|
2778
2849
|
/**
|
|
2779
2850
|
* Transforms a payload value as it crosses the store boundary — e.g. encrypt-at-rest, compress, or
|
|
2780
2851
|
* redact PII. `decode` must be the exact inverse of `encode`. Both are synchronous (use a local
|
|
@@ -2838,6 +2909,9 @@ declare class CodecStateStore implements StateStore {
|
|
|
2838
2909
|
declare function eventPrefix(name: string): string;
|
|
2839
2910
|
/** Build the unique waiter token for one `waitForEvent` call (name + match + run position). */
|
|
2840
2911
|
declare function eventToken(name: string, match: Record<string, unknown> | undefined, runId: string, seq: number): string;
|
|
2912
|
+
/** The event name embedded in an event waiter token (the 2nd `:`-segment is the base64 name), so a
|
|
2913
|
+
* dashboard can show "waiting on event `<name>`" instead of the opaque token. */
|
|
2914
|
+
declare function eventNameOf(token: string): string;
|
|
2841
2915
|
/** The match criteria embedded in an event waiter token (the 3rd `:`-segment is the base64 match). */
|
|
2842
2916
|
declare function eventMatchOf(token: string): Record<string, unknown>;
|
|
2843
2917
|
/** Whether `payload` satisfies a waiter's `match`: every match key deep-equals the payload's value. */
|
|
@@ -3152,4 +3226,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
|
|
|
3152
3226
|
onControl(handler: (msg: ControlMessage) => void): void;
|
|
3153
3227
|
}
|
|
3154
3228
|
|
|
3155
|
-
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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, WORKFLOW_NAME_KEY, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventPrefix, eventToken, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
|
|
3229
|
+
export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, type ScheduledWorkflow, type SearchAttributes, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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, WORKFLOW_NAME_KEY, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, classifyWaiterToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, indexWaitersByRun, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
|
package/dist/index.js
CHANGED
|
@@ -780,6 +780,14 @@ function eventToken(name, match, runId, seq) {
|
|
|
780
780
|
return `${eventPrefix(name)}${enc(JSON.stringify(match ?? {}))}:${runId}#${seq}`;
|
|
781
781
|
}
|
|
782
782
|
__name(eventToken, "eventToken");
|
|
783
|
+
function eventNameOf(token) {
|
|
784
|
+
try {
|
|
785
|
+
return dec(token.split(":")[1] ?? "");
|
|
786
|
+
} catch {
|
|
787
|
+
return token;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
__name(eventNameOf, "eventNameOf");
|
|
783
791
|
function eventMatchOf(token) {
|
|
784
792
|
try {
|
|
785
793
|
return JSON.parse(dec(token.split(":")[2] ?? ""));
|
|
@@ -1720,6 +1728,7 @@ var WorkflowEngine = class {
|
|
|
1720
1728
|
leaseMs;
|
|
1721
1729
|
maxRecoveryAttempts;
|
|
1722
1730
|
remoteAdvanceSilenceMs;
|
|
1731
|
+
reconcileMs;
|
|
1723
1732
|
webhookUrl;
|
|
1724
1733
|
traceparent;
|
|
1725
1734
|
context;
|
|
@@ -1790,6 +1799,7 @@ var WorkflowEngine = class {
|
|
|
1790
1799
|
this.leaseMs = deps.leaseMs ?? 3e4;
|
|
1791
1800
|
this.maxRecoveryAttempts = deps.maxRecoveryAttempts;
|
|
1792
1801
|
this.remoteAdvanceSilenceMs = deps.remoteAdvanceSilenceMs;
|
|
1802
|
+
this.reconcileMs = deps.reconcileMs === void 0 ? 3e5 : deps.reconcileMs || void 0;
|
|
1793
1803
|
this.webhookUrl = deps.webhookUrl;
|
|
1794
1804
|
this.traceparent = deps.traceparent;
|
|
1795
1805
|
this.context = deps.context;
|
|
@@ -3134,7 +3144,7 @@ var WorkflowEngine = class {
|
|
|
3134
3144
|
}
|
|
3135
3145
|
await this.store.updateRun(run.id, {
|
|
3136
3146
|
status: "suspended",
|
|
3137
|
-
wakeAt: outcome.wakeAt,
|
|
3147
|
+
wakeAt: this.reconcileWakeAt(outcome.wakeAt),
|
|
3138
3148
|
updatedAt
|
|
3139
3149
|
});
|
|
3140
3150
|
this.emit({
|
|
@@ -3148,6 +3158,16 @@ var WorkflowEngine = class {
|
|
|
3148
3158
|
status: "suspended"
|
|
3149
3159
|
};
|
|
3150
3160
|
}
|
|
3161
|
+
/**
|
|
3162
|
+
* A wakeAt to persist on a suspend: the natural timer if the turn produced one (a `ctx.sleep`, a
|
|
3163
|
+
* remote-step deadline), else the {@link reconcileMs} fallback so an event-waiting run (child/signal/
|
|
3164
|
+
* timeout-less remote step) can't be orphaned forever if its wake is lost. `undefined` only when the
|
|
3165
|
+
* fallback is disabled (`reconcileMs: 0`). See {@link WorkflowEngineDeps.reconcileMs}.
|
|
3166
|
+
*/
|
|
3167
|
+
reconcileWakeAt(wakeAt) {
|
|
3168
|
+
if (wakeAt != null) return wakeAt;
|
|
3169
|
+
return this.reconcileMs != null ? this.clock() + this.reconcileMs : void 0;
|
|
3170
|
+
}
|
|
3151
3171
|
async runRemoteExecution(run, registered) {
|
|
3152
3172
|
if (run.status === "cancelling") {
|
|
3153
3173
|
const error = {
|
|
@@ -4283,6 +4303,42 @@ var TERMINAL_RUN_STATUSES = [
|
|
|
4283
4303
|
"dead"
|
|
4284
4304
|
];
|
|
4285
4305
|
|
|
4306
|
+
// src/run-waiting.ts
|
|
4307
|
+
var WEBHOOK_PREFIX = "wh:";
|
|
4308
|
+
var CHILD_PREFIX = "child:";
|
|
4309
|
+
var EVENT_PREFIX = "event:";
|
|
4310
|
+
function classifyWaiterToken(token) {
|
|
4311
|
+
if (token.startsWith(WEBHOOK_PREFIX)) return {
|
|
4312
|
+
on: "webhook",
|
|
4313
|
+
name: token
|
|
4314
|
+
};
|
|
4315
|
+
if (token.startsWith(CHILD_PREFIX)) return {
|
|
4316
|
+
on: "child",
|
|
4317
|
+
name: token.slice(CHILD_PREFIX.length)
|
|
4318
|
+
};
|
|
4319
|
+
if (token.startsWith(EVENT_PREFIX)) return {
|
|
4320
|
+
on: "signal",
|
|
4321
|
+
name: eventNameOf(token)
|
|
4322
|
+
};
|
|
4323
|
+
return {
|
|
4324
|
+
on: "signal",
|
|
4325
|
+
name: token
|
|
4326
|
+
};
|
|
4327
|
+
}
|
|
4328
|
+
__name(classifyWaiterToken, "classifyWaiterToken");
|
|
4329
|
+
function resolveRunWaiting(run, waiterByRun) {
|
|
4330
|
+
if (run.status !== "suspended") return void 0;
|
|
4331
|
+
const waiter = waiterByRun.get(run.id);
|
|
4332
|
+
return waiter ? classifyWaiterToken(waiter.token) : void 0;
|
|
4333
|
+
}
|
|
4334
|
+
__name(resolveRunWaiting, "resolveRunWaiting");
|
|
4335
|
+
function indexWaitersByRun(waiters) {
|
|
4336
|
+
const byRun = /* @__PURE__ */ new Map();
|
|
4337
|
+
for (const w of waiters) if (!byRun.has(w.runId)) byRun.set(w.runId, w);
|
|
4338
|
+
return byRun;
|
|
4339
|
+
}
|
|
4340
|
+
__name(indexWaitersByRun, "indexWaitersByRun");
|
|
4341
|
+
|
|
4286
4342
|
// src/codec-state-store.ts
|
|
4287
4343
|
var CodecStateStore = class {
|
|
4288
4344
|
static {
|
|
@@ -5037,17 +5093,21 @@ export {
|
|
|
5037
5093
|
attributeOperand,
|
|
5038
5094
|
bindWorkflowClass,
|
|
5039
5095
|
breakpointToken,
|
|
5096
|
+
classifyWaiterToken,
|
|
5040
5097
|
collectMetrics,
|
|
5041
5098
|
createStepLogger,
|
|
5042
5099
|
currentWorkflowCtx,
|
|
5043
5100
|
eventMatchOf,
|
|
5044
5101
|
eventMatches,
|
|
5102
|
+
eventNameOf,
|
|
5045
5103
|
eventPrefix,
|
|
5046
5104
|
eventToken,
|
|
5105
|
+
indexWaitersByRun,
|
|
5047
5106
|
matchesAttributes,
|
|
5048
5107
|
normalizeAttributeRows,
|
|
5049
5108
|
parseDuration,
|
|
5050
5109
|
prevCronFireMs,
|
|
5110
|
+
resolveRunWaiting,
|
|
5051
5111
|
runInWorkflowCtx,
|
|
5052
5112
|
runSchedules,
|
|
5053
5113
|
runStepHandler,
|