Graceful Shutdown: In‑flight requests during zero‑downtime migration
0 reputation · 08 Oct 2021, 15:44 UTC
0 reputation · 08 Oct 2021, 15:44 UTC
We need to migrate a small Ktor application without service interruption. The plan relies on Ktor’s Graceful Shutdown, which stops accepting new connections and waits for existing requests to finish.
The default gracefulShutdownTimeout is 30 s, and any new request after shutdown begins receives a 503 Service Unavailable. Long‑running handlers may exceed the timeout, causing abrupt termination.
gracefulShutdownTimeout—do they abort immediately or after the timeout?35275 reputation · 08 Oct 2021, 19:59 UTC
Requests exceeding the timeout abort after the timeout, not immediately. Ktor's stop(gracePeriodMillis, timeoutMillis) (and the equivalent engine configuration) stops accepting new connections, waits up to the grace period for in-flight requests to finish, and then forcibly terminates whatever is still running once the timeout elapses. A handler that sleeps past the limit is cancelled mid-flight — the client sees a reset or truncated connection.
The 503 for new connections is effectively not customizable. That response is engine behavior (CIO/Netty/Jetty), not a documented application hook. There is no supported API to change the status code during shutdown, so treat 503 as fixed at the server level. If you need a different signal, put it in front of Ktor (load balancer or proxy), not inside it.
There is no built-in guarantee that all in-flight requests complete. Ktor only waits up to the configured timeout. For non-idempotent operations, the timeout is a backstop, not a correctness mechanism — a terminated handler can leave partial writes or half-committed transactions.
isActive or use structured concurrency so a cancelled request rolls back cleanly instead of committing partial state.Exact configuration keys differ across Ktor 1.x/2.x/3.x and across engines — newer versions expose shutdown grace/timeout in the connector configuration, while older code calls stop(gracePeriod, timeout) directly. Confirm the parameter names and the stated 30 s default against the Ktor version you actually run; treat that default as unverified until checked.
One detail that would change this recommendation: whether your long-running handlers are idempotent. If they are, infrastructure-level draining plus a sane timeout is enough; if they are not, application-level tracking and cancellation-aware rollback are mandatory, not optional.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.