import type { ChildProcess } from 'node:child_process'; import * as sessionStore from '../services/session-store.js'; import type { DaemonSession } from './types.js'; type ShutdownPhaseResult = { ok: boolean; taskId: string | null; error?: string; }; export type PreparedRemoteShutdown = { ok: true; fence: 'prepared'; requestId: string; taskId: string | null; /** Runtime lineage sampled before the worker fence. A workerless transaction * must still own this exact value at persistence time; a live transaction may * advance only to its drained `taskId`. */ runtimeTaskIdAtPrepare: string | null; /** Fresh durable lineage sampled before installing the fence. Phase 2 uses * it as a lock-protected compare-and-set guard, while also accepting an * already-idempotent target written by the ordinary task-id callback. */ durableTaskIdAtPrepare: string | null; durableOwnerAtPrepare: { pid: number | null; larkAppId: string | null; backendType: string | null; }; /** Set only after the exact cross-process fresh read succeeds. Used when a * prepared worker exits before an all-or-nothing rollback can reach it. */ lineageVerified: boolean; /** Exact generation fenced by `requestId`. Null means the active logical * session was already workerless and only its runtime lineage needs an exact * durable verification. */ worker: ChildProcess | null; }; export type RemoteShutdownFailure = { ok: false; requestId?: string; taskId: string | null; error: string; /** Phase-2 coordinator policy. Ownership ambiguity must stay fenced; a * plain atomic-write I/O failure may restore the exact prepared worker. */ rollbackDisposition?: 'abort_safe' | 'retain_fence'; }; /** A prepare refusal that is proven to have happened before the worker/backend * fence. It must never be sent an abort request. */ export type UnfencedRemoteShutdownRefusal = RemoteShutdownFailure & { fence: 'none'; }; /** A prepare attempt whose exact worker may have installed its backend fence. * Preparation deliberately does not restore admission inline; the fleet * coordinator includes this handle in its one concurrent abort wave. */ export type PossiblyFencedRemoteShutdown = RemoteShutdownFailure & { fence: 'possible'; requestId: string; worker: ChildProcess; expectedAbortTaskId?: string | null; }; export type RemoteShutdownPrepareResult = PreparedRemoteShutdown | UnfencedRemoteShutdownRefusal | PossiblyFencedRemoteShutdown; export type RemoteShutdownPrepareOptions = { drainTimeoutMs?: number; abortTimeoutMs?: number; /** Absolute transaction deadline. A worker is never asked to fence unless * phase-2 plus the configured admission-restore reserve remain after drain. */ deadlineMs?: number; now?: () => number; /** One projection sampled by prepareRemoteFleetForShutdown before any fence. */ durableSnapshot?: sessionStore.ActiveRemoteShutdownSnapshot; }; export type RemoteFleetPrepareEntry = { ds: DaemonSession; result: RemoteShutdownPrepareResult; }; export type FencedRemoteShutdownParticipant = PreparedRemoteShutdown | PossiblyFencedRemoteShutdown; export type UniqueDaemonShutdownSessions = { ok: true; sessions: DaemonSession[]; } | { ok: false; sessionId: string; error: string; }; /** The active registry can retain multiple aliases to one exact runtime object * after transfer/restore. Process that object once, but refuse two distinct * objects claiming the same durable session id: there is no unique generation * that shutdown can safely fence or retire. */ export declare function collectUniqueDaemonShutdownSessions(candidates: Iterable): UniqueDaemonShutdownSessions; export type RemoteShutdownDetachOutcome = { ok: true; requestId: string; taskId: string | null; disposition: 'lineage_persisted'; worker?: ChildProcess; } | RemoteShutdownFailure; /** Phase 1: fence one exact remote generation and drain lineage materialization. * Nothing exits or restores admission here. A failure after the prepare send * returns an exact possibly-fenced handle so all peers can be restored in one * concurrent fleet wave rather than serial drain+abort chains. */ export declare function prepareRemoteSessionForShutdown(ds: DaemonSession, options?: RemoteShutdownPrepareOptions): Promise; export type RemoteFleetPrepareOptions = Omit & { snapshotTimeoutMs?: number; }; /** Take one fresh projection for the complete candidate set, then (and only * then) publish prepare requests concurrently. */ export declare function prepareRemoteFleetForShutdown(candidates: readonly DaemonSession[], options?: RemoteFleetPrepareOptions): Promise; export type PreparedRemoteFleetEntry = { ds: DaemonSession; result: PreparedRemoteShutdown; }; export type RemoteFleetPersistenceResult = { ok: true; } | (RemoteShutdownFailure & { sessionIds: readonly string[]; retainFencedSessionIds: readonly string[]; }); /** Phase 2 fleet transaction: validate every runtime generation, then compare * and publish all durable lineage rows with one lock and one rename. */ export declare function persistPreparedRemoteShutdownFleet(entries: readonly PreparedRemoteFleetEntry[], options?: { persistTimeoutMs?: number; deadlineMs?: number; now?: () => number; }): RemoteFleetPersistenceResult; /** Single-session compatibility path. Fleet shutdown uses the batch function * above; this API remains for explicit focused operations and older callers. */ export declare function persistPreparedRemoteShutdown(ds: DaemonSession, prepared: PreparedRemoteShutdown): { ok: true; } | RemoteShutdownFailure; export declare function isPreparedRemoteSessionCurrent(ds: DaemonSession, prepared: PreparedRemoteShutdown): boolean; /** After verified lineage persistence, an exact prepared worker that exited * and was cleared by worker-pool can be safely rolled back locally. A new * worker generation or a different fence remains ownership ambiguity. */ export declare function canAbortVerifiedExitedRemotePreparation(ds: DaemonSession, prepared: PreparedRemoteShutdown): boolean; /** Roll back one prepared participant. State clears only after the exact worker * ACKs admission restoration; timeout/late ACK remains deliberately fail-closed. */ export declare function abortPreparedRemoteShutdown(ds: DaemonSession, prepared: PreparedRemoteShutdown, options?: { abortTimeoutMs?: number; }): Promise; export type RemoteFleetAbortEntry = { ds: DaemonSession; result: FencedRemoteShutdownParticipant; }; export type RemoteFleetAbortResult = { ds: DaemonSession; participant: FencedRemoteShutdownParticipant; result: ShutdownPhaseResult; }; /** Restore every exact prepared/possibly-fenced generation concurrently. No * participant can consume another's timeout budget. */ export declare function abortRemoteShutdownFleet(entries: readonly RemoteFleetAbortEntry[], options?: { abortTimeoutMs?: number; deadlineMs?: number; now?: () => number; }): Promise; /** Phase 3: synchronous, infallible-after-validation commit. The coordinator * validates every participant first, then calls this without an intervening * await, so one session can never refuse after a peer was detached. */ export declare function commitPreparedRemoteShutdown(ds: DaemonSession, prepared: PreparedRemoteShutdown): boolean; /** Single-session compatibility wrapper. Daemon shutdown intentionally uses * the explicit three-phase API above so a multi-backend remote fleet cannot * half-commit. */ export declare function detachRemoteWorkerForShutdown(ds: DaemonSession, options?: { drainTimeoutMs?: number; abortTimeoutMs?: number; }): Promise; export {}; //# sourceMappingURL=remote-shutdown-detach.d.ts.map