import { HUNG_UPDATE_GRACE_MS } from "@fjall/util"; import type { StackResourceStatusRead, StackStatusRead } from "../../aws/utils/cloudformationEventTypes.js"; import type { EcsRollbackVerdict, EcsRollbackVerdictSource } from "../../types/ecsRollbackVerdict.js"; import type { CancelInFlightOutcome } from "./cancelInFlightStack.js"; export { HUNG_UPDATE_GRACE_MS }; /** What the watch has seen of one verdict's resource since the rollback. */ export interface ResourceSilence { /** When the current silence began, on the local clock. */ readonly sinceMs: number; /** The resource's `LastUpdatedTimestamp` at the last read. */ readonly lastUpdated: Date; } /** What one read of a verdict's stack and resource decides. */ export type HungUpdateDecision = { readonly kind: "cancel"; } | { readonly kind: "wait"; readonly silence: ResourceSilence; } | { readonly kind: "unreadable"; readonly read: string; readonly reason: string; } | { readonly kind: "never"; /** `stack`: nothing in this stack's update will be cancelled. */ readonly scope: "stack" | "resource"; readonly reason: string; }; /** * Decide, from one fresh read of the stack and of the verdict's resource, * whether to cancel the stack's update. Pure: `silence` is what the previous * reads saw, and a `wait` carries what this one adds. */ export declare function decideHungUpdate(input: { readonly verdict: EcsRollbackVerdict; readonly stack: StackStatusRead; readonly resource: StackResourceStatusRead; readonly silence: ResourceSilence | undefined; readonly nowMs: number; }): HungUpdateDecision; /** The cancel the watch issued. */ export interface HungUpdateCancel { readonly stackName: string; readonly verdict: EcsRollbackVerdict; /** * False when CloudFormation's answer to the cancel was lost and the stack * was next read rolling back: the cancel may have begun the rollback. */ readonly confirmed: boolean; } /** What a deploy hands the engine so it can end an update CloudFormation stopped driving. */ export interface HungUpdateWatchOptions { /** The deploy's ECS tail. */ readonly verdicts: EcsRollbackVerdictSource; /** A warning event for each notice, beside its output line. */ readonly onWarning: (message: string) => void; } /** ECS's verdict, as one clause. */ export declare function describeRollbackVerdict(verdict: EcsRollbackVerdict): string; /** * A deploy's failure after the watch cancelled its update: ECS's verdict, not * the "Resource update cancelled" root cause the cancel leaves behind. * `outcome` says where the stack got to. */ export declare function hungUpdateCancelFailure(cancel: HungUpdateCancel, outcome: string): string; export interface HungUpdateWatchDeps { /** The deploy's ECS tail, read on every tick. */ readonly verdicts: EcsRollbackVerdictSource; /** The stack the deploy is updating, once it is known. */ readonly stackName: () => string | undefined; readonly readStack: (stackName: string) => Promise; readonly readResource: (stackName: string, logicalId: string) => Promise; /** * Sends CancelUpdateStack with `clientRequestToken`, one per watch, so * CloudFormation takes a resend of a cancel it already took as that one. */ readonly cancel: (stackName: string, clientRequestToken: string) => Promise; /** * One operator-facing notice. Built only from identifiers and reasons * masked where they were read, so the sink adds no second mask. */ readonly notify: (message: string) => void; /** Ends the watch. The watch never fires it, and never fires the deploy's. */ readonly stopSignal: AbortSignal; /** Test seams. */ readonly pollIntervalMs?: number; readonly now?: () => number; } export interface HungUpdateWatch { /** Settles once the watch has stopped; never rejects. */ readonly settled: Promise; /** The cancel the watch issued, once it has. */ cancelled(): HungUpdateCancel | undefined; } /** * Watch a deploy's ECS rollback verdicts, and cancel the stack's update once * `decideHungUpdate` says so: at most one cancel per watch, sent again on the * next tick when CloudFormation could not be read, refused it, or its answer * was lost. After a lost answer, a stack next read rolling back records the * cancel as unconfirmed. */ export declare function startHungUpdateWatch(deps: HungUpdateWatchDeps): HungUpdateWatch;