How to Implement Graceful Shutdown in Spring Boot 2.3 and Avoid Data Loss
Learn how Spring Boot 2.3’s built-in graceful shutdown works, configure it with server.shutdown=graceful, understand shutdown phases, timeout settings, and see code examples for handling shutdown hooks and actuator endpoints, ensuring active requests finish without data inconsistency across Tomcat, Jetty, Netty, and Undertow.
What Is Graceful Shutdown?
When a Spring Boot application receives a request that takes time (e.g., a 20‑second Thread.sleep), killing the process will abruptly stop the embedded container, causing the request to fail and potentially leaving data inconsistent.
Graceful Shutdown in Spring Boot 2.3
Since Spring Boot 2.3, graceful shutdown is built‑in for embedded servers (Tomcat, Jetty, Undertow, Reactor Netty). Enable it by setting
server.shutdown=graceful. The server stops accepting new requests and waits for active ones to finish within a configurable timeout.
Configuration Details
Shutdown Enum
<code>/**
* Configuration for shutting down a {@link WebServer}.
*
* @author Andy Wilkinson
* @since 2.3.0
*/
public enum Shutdown {
/**
* Graceful shutdown (bounded).
*/
GRACEFUL,
/**
* Immediate shutdown.
*/
IMMEDIATE;
}
</code>Shutdown Phase Timeout
The default timeout is 30 seconds; after this period the application shuts down regardless of ongoing tasks.
Effect Demonstration
Send a request to the endpoint (image).
Trigger application shutdown (image).
The server receives the shutdown command and waits for the request to complete.
Log output shows the graceful shutdown lifecycle.
<code>2020-05-17 18:28:28.940 INFO 60341 --- [extShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2020-05-17 18:28:45.923 INFO 60341 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
</code>Related Knowledge
Use kill -2 (Ctrl+C) to trigger Java’s ShutdownHook for graceful shutdown; kill -9 forces termination without invoking hooks.
<code>// ApplicationContext shutdown hook registration
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
</code>Spring Boot also provides an actuator endpoint
/actuator/shutdownto initiate graceful shutdown programmatically.
<code>@Endpoint(id = "shutdown", enableByDefault = false)
public class ShutdownEndpoint implements ApplicationContextAware {
@WriteOperation
public Map<String, String> shutdown() {
Thread thread = new Thread(this::performShutdown);
thread.setContextClassLoader(getClass().getClassLoader());
thread.start();
}
private void performShutdown() {
try {
Thread.sleep(500L);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
this.context.close();
}
}
</code>Container‑Specific Behavior
Tomcat 9.0.33+ : Stops accepting new requests; client requests wait until timeout.
Reactor Netty : Same as Tomcat.
Undertow : Stops accepting new requests; new client requests receive HTTP 503 immediately.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
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.