diff --git a/fleetd/src/main/java/dev/ltms/fleet/session/SessionManager.java b/fleetd/src/main/java/dev/ltms/fleet/session/SessionManager.java index 5ffa5b8..75ab15c 100644 --- a/fleetd/src/main/java/dev/ltms/fleet/session/SessionManager.java +++ b/fleetd/src/main/java/dev/ltms/fleet/session/SessionManager.java @@ -864,10 +864,20 @@ public final class SessionManager implements TurnListener { } /** - * Gracefully drain all registered sessions on daemon shutdown. For each session that is - * {@code BUSY}, poll up to {@code timeoutNanos} for it to leave {@code BUSY}, then release it - * regardless. Non-busy sessions are released immediately. A failure releasing one session is - * logged and does not abort the rest. + * Gracefully drain all registered sessions on daemon shutdown. Non-busy sessions are released + * immediately; a {@code BUSY} one is polled until it leaves {@code BUSY}, then released + * regardless. A failure releasing one session is logged and does not abort the rest. + * + *
{@code timeoutNanos} is a budget for the WHOLE drain, not a grace period per session: the + * deadline is taken once, before the loop. So the first BUSY session can spend all of it, and a + * later BUSY one is then released with no wait at all. That is deliberate. This drain is only + * one phase of shutdown — {@code Fleetd} closes the message service, the push loop, the + * heartbeat, MCP and the router after it — and the whole sequence has to finish inside + * launchd's exit window. A per-session grace would let N busy members drain for N * the + * timeout, overrun that window, and get the daemon SIGKILLed part-way through; the members not + * yet reached would then get no clean release, no preserved-worktree log, and no snapshot. + * Cutting one turn short is the cheaper failure, and it is not silent: an abandoned BUSY + * session is preserved, snapshotted, and logged at WARN by {@code logPreservedForShutdown}. * *
CB-544: this is a {@link ReleaseCause#SHUTDOWN} release — the worker's pane is stopped * (the process must end) but its worktree is preserved and its path logged. Shutdown is never