/** * The `runFinalizerActivity` primitive (#446 Phase 2). A workflow's definition-level * `finalizer` is an ordinary activity, but it runs POST-terminal — after the engine * has evicted the workflow's generator and abort controller — so it cannot go through * the live-workflow `executeActivity` path: that path reads * `inlineStrategy.getAbortController(workflowId)` (gone after cancel) and the * per-workflow type/heartbeat bookkeeping (swept by terminal cleanup). This primitive * therefore owns its OWN `AbortController`, resolves the implementation from the * engine-lifetime registration entry, and never touches the operation-result feedback * channel. * * Outer retry/backoff is the teardown timer reschedule in `runWorkflowFinalizer`, NOT * the activity's own `retry` policy — so this primitive runs exactly one attempt and * surfaces success or a thrown error to the caller. The activity's `timeout` is honored * as a per-attempt cap. * * @module core/engine/termination/finalizer-activity */ import type { ActivityContext, Duration } from '../../types.ts'; /** * The minimal finalizer shape this primitive uses. A registered finalizer is stored * as `AnyActivityDefinition`, whose `execute` is typed `ActivityFunction` (the * input is contravariantly `never`) and which erases `timeout` at the type level — * neither shape is directly invokable with `unknown` input. The drive narrows the * registry entry to this structural type, which is what the engine actually relies on * at teardown: a named, callable activity with an optional per-attempt `timeout`. */ export interface RunnableFinalizer { readonly name: string; readonly timeout?: Duration; execute(input: unknown, context?: ActivityContext): unknown; } /** Outcome of a single finalizer attempt. */ export type FinalizerAttemptResult = { ok: true; } | { ok: false; error: unknown; abortedByShutdown: boolean; }; /** * Run one attempt of a workflow's finalizer activity against the recorded finalizer * state, under a caller-supplied abort signal (the engine shutdown signal) composed * with the activity's own per-attempt timeout. Resolves to a structured result rather * than throwing, so the drive can branch on success / retryable-failure / dead-letter * without a try/catch around it. * * @param finalizer - the resolved finalizer activity definition (from the engine-lifetime registry) * @param input - the decoded `ctx.setFinalizerState` payload passed as the activity input * @param attempt - 1-based attempt number, for the per-attempt timeout error message * @param shutdownSignal - the engine's dispose/shutdown abort signal; aborting it stops a cooperating finalizer */ export declare function runFinalizerActivity(finalizer: RunnableFinalizer, input: unknown, attempt: number, shutdownSignal: AbortSignal, workflowExecutionToken?: string): Promise;