Graceful Shutdown in Spring Boot 2.3.4: Configuration, Code Examples, and Shutdown Mechanisms
This article explains how Spring Boot 2.3.4 implements graceful shutdown for Jetty, Reactor Netty, Tomcat and Undertow, shows the simple YAML configuration, demonstrates code examples using DisposableBean and @PreDestroy, and describes the actuator shutdown endpoint and its relevance to Kubernetes liveness and readiness probes.
Graceful Shutdown
Spring Boot 2.3.4 introduces improved graceful shutdown support for Jetty, Reactor Netty, Tomcat, and Undertow, applicable to both reactive and servlet‑based web applications.
The purpose of graceful shutdown is to avoid abrupt termination (kill -9) that can cause in‑flight requests to fail and produce dirty data.
When graceful shutdown is enabled, the server reserves a short period after receiving a SIGINT (kill -2) during which no new requests are accepted and existing requests are allowed to complete. Different servers handle new requests differently: Reactor Netty and Tomcat stop accepting, Undertow returns 503.
New Configuration
YAML Configuration
The new configuration is simple: set server.shutdown=graceful. This requires Tomcat 9.0.33 or newer.
server:
port: 6080
shutdown: graceful # enable graceful shutdown
spring:
lifecycle:
timeout-per-shutdown-phase: 20s # buffer time, default 30sAfter configuring timeout-per-shutdown-phase, if a thread cannot finish within the buffer time it will be forced to stop.
Logs with and without graceful shutdown differ; with graceful shutdown you will see “Waiting for active requests to complete” before the container stops.
Shutdown Methods
Do not use kill -9; use kill -2 to trigger the JVM shutdown hook. Alternatively, invoke the /actuator/shutdown endpoint via a POST request.
Adding a ShutdownHook
Implement DisposableBean and override destroy(), or annotate a method with @PreDestroy. The @PreDestroy method runs before the DisposableBean method.
@Slf4j
@Service
public class DefaultDataStore implements DisposableBean {
private final ExecutorService executorService = new ThreadPoolExecutor(
OSUtil.getAvailableProcessors(),
OSUtil.getAvailableProcessors() + 1,
1,
TimeUnit.MINUTES,
new ArrayBlockingQueue<>(200),
new DefaultThreadFactory("UploadVideo"));
@Override
public void destroy() throws Exception {
log.info("Preparing graceful shutdown using DisposableBean");
executorService.shutdown();
}
} @Slf4j
@Service
public class DefaultDataStore {
private final ExecutorService executorService = new ThreadPoolExecutor(
OSUtil.getAvailableProcessors(),
OSUtil.getAvailableProcessors() + 1,
1,
TimeUnit.MINUTES,
new ArrayBlockingQueue<>(200),
new DefaultThreadFactory("UploadVideo"));
@PreDestroy
public void shutdown() {
log.info("Preparing graceful shutdown @PreDestroy");
executorService.shutdown();
}
}The shutdown process ultimately calls this.context.close(), which invokes AbstractApplicationContext.doClose() to destroy beans and remove the JVM shutdown hook.
Shutdown Endpoint
Spring Boot’s actuator provides a ShutdownEndpoint (disabled by default). When enabled, a POST to /actuator/shutdown triggers the same graceful shutdown logic.
@Configuration(proxyBeanMethods = false)
@ConditionalOnAvailableEndpoint(endpoint = ShutdownEndpoint.class)
public class ShutdownEndpointAutoConfiguration {
@Bean(destroyMethod = "")
@ConditionalOnMissingBean
public ShutdownEndpoint shutdownEndpoint() {
return new ShutdownEndpoint();
}
}The endpoint’s shutdown() method checks the application context, performs the shutdown, and returns a status map.
Afterword
Graceful shutdown in a single‑node Spring Boot application only guarantees that the server’s internal threads finish; client‑side state is not handled. In distributed systems (Dubbo, cloud services), you must deregister the service from the registry before stopping it to avoid 503 errors.
Kubernetes integration in Spring Boot 2.3 adds Liveness and Readiness probes, which help manage container lifecycle and traffic routing during shutdown.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
