Envoy hot restart drain stalls on long-lived connections during migration
0 reputation · 05 Jul 2023, 10:26 UTC
0 reputation · 05 Jul 2023, 10:26 UTC
Plan a zero-downtime migration for a small application behind Envoy using hot restart and graceful draining. The old worker must release existing connections and exit within the maintenance window while the new worker accepts traffic.
Long-lived connections such as WebSocket sessions or gRPC streams may delay draining until they close or reach idle timeout. Drain timeout behavior differs by Envoy version and operating system, and hot restart is not enabled in every build configuration. It is unclear whether the old process is forced to stop after the drain timeout or whether persistent connections can block migration indefinitely.
34275 reputation · 05 Jul 2023, 11:48 UTC
Envoy sends a SIGKILL to the old worker process once the configured drain_timeout expires, regardless of whether long-lived connections such as WebSocket sessions or gRPC streams are still active. The process exit sequence prioritizes the drain timeout as a hard limit. However, the exact enforcement can vary by Envoy version and operating system; older builds may not signal the kill as consistently, and OS-level signal handling differences can affect timing.
Yes. When the drain timeout expires, Envoy forcibly closes active connections, which typically results in a TCP RST or a stream-level error on the client. Adding idempotent retry logic with exponential backoff and respect for Retry-After or equivalent headers absorbs these failures without surfacing errors to end users. This is especially critical for gRPC streams and WebSocket connections, where a sudden close can lose in-flight data.
During a hot restart the new Envoy process takes over the listener file descriptors immediately. The old process enters a draining state where it stops accepting new connections but continues to serve existing ones. The drain_timeout acts as the overall process-exit deadline, while listener_idle_timeout only closes connections that have been inactive for its configured interval. In practice the drain timeout takes precedence: if the old process has not exited within the drain timeout Envoy kills it. The listener idle timeout may close stale connections earlier but it does not override the drain timeout's hard stop.
drain_timeout to a value that exceeds the longest expected long-lived connection duration. The default is 300 seconds; adjust upward for gRPC streams or WebSocket sessions that may persist for minutes to hours.listener_idle_timeout separately if you want Envoy to close inactive connections before the drain timeout expires. This does not affect the process-exit deadline but can reduce the number of connections the old process must drain.To refine the recommendation for your specific environment it would help to know the current drain_timeout value and the Envoy version in use.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.