Preserve verified health when provisioning completes

This commit is contained in:
2026-10-06 15:48:38 -04:00
parent 6999a33aef
commit 57d2bd11db
9 changed files with 256 additions and 41 deletions
+16 -3
View File
@@ -23,11 +23,24 @@ export function restartRecoveryPending(server: string): boolean {
return slotFor(server)?.healthy_at === null;
}
/** The queued restart may still expose the previous healthy container. */
type SettlingSlot = Pick<RestartSlot, 'requested_at' | 'healthy_at' | 'operation_id'>;
interface SettlingOperation { id: string; action: string; state: string }
/** Submitted lifecycle work stays Starting until verification ends, including slow restarts. */
export function recoverySettling(slot: SettlingSlot | undefined, operation?: SettlingOperation | null): boolean {
if (!slot || slot.healthy_at) return false;
if (slot.operation_id) return operation?.id === slot.operation_id
&& ['start', 'restart', 'rebuild'].includes(operation.action)
&& ['running', 'awaiting-health'].includes(operation.state);
// Legacy recovery slots have no operation whose verification can be followed.
return Date.now() - Date.parse(slot.requested_at) < HEALTH_POLL_MS;
}
export function restartSettling(server: string): boolean {
const slot = slotFor(server);
return !!(slot && !slot.healthy_at
&& Date.now() - Date.parse(slot.requested_at) < HEALTH_POLL_MS);
const operation = slot?.operation_id ? db().prepare(`SELECT id, action, state FROM server_deployments
WHERE server = ? AND server_deleted_at IS NULL ORDER BY rowid DESC LIMIT 1`).get(server) as SettlingOperation | undefined : undefined;
return recoverySettling(slot, operation);
}
export function rolloutWaitReason(server: string, operationId = '', action: RuntimeAction = 'restart'): string | null {