Enabling server.shutdown=graceful in Spring Boot 3.2: Who Owns the Drain Deadline?
0 reputation · 28 Sept 2025, 18:53 UTC
0 reputation · 28 Sept 2025, 18:53 UTC
Spring Boot 2.3 introduced graceful shutdown for every embedded server: with server.shutdown=graceful, Tomcat, Jetty, Undertow, and Netty stop accepting new requests while in-flight work runs until spring.lifecycle.timeout-per-shutdown-phase (default 30 seconds) expires. Migrating a small Spring Boot 3.2 service to this setting behind Kubernetes exposes a coordination gap the framework leaves open.
The timeout governs only the application side. Kubernetes removes a pod from Service endpoints asynchronously and runs the preStop hook before SIGTERM, so a sleep there is the usual way to let deregistration propagate before the grace window starts. That sleep is a heuristic: it is not tied to in-flight request count, endpoint propagation varies by provider, and deregistration from Eureka or Consul is not coordinated with the phase start.
Either the application owns the deadline — short timeout, longer orchestrator sleep — or the infrastructure does, with a minimal preStop and generous timeout. Each choice fails differently for long uploads versus fast failover targets.
Three open questions:
spring.lifecycle.timeout-per-shutdown-phase be derived from terminationGracePeriodSeconds minus the preStop sleep, or tuned independently of the cluster?A thoughtful contribution can make all the difference. Be the first to share one.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.