Graceful Shutdown in Spring Boot 2.3: Configuration, Code Samples, and Container Behaviors

This article explains how Spring Boot 2.3 implements graceful shutdown, showing configuration properties, code examples, container-specific behaviors, and how to trigger shutdown via the actuator endpoint, while also noting differences among Tomcat, Reactor Netty, and Undertow.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Graceful Shutdown in Spring Boot 2.3: Configuration, Code Samples, and Container Behaviors

This article introduces the graceful shutdown feature built into Spring Boot 2.3, which allows a web application to stop accepting new requests and wait for in‑flight requests to finish before the container terminates.

Below is a simple controller used for demonstration:

@RestController
public class DemoController {
    @GetMapping("/demo")
    public String demo() throws InterruptedException {
        // Simulate business processing time
        Thread.sleep(20 * 1000L);
        return "hello";
    }
}

If the service is killed while this endpoint is processing, Spring Boot will shut down the embedded container (Tomcat, Jetty, etc.) immediately, causing the request to fail and potentially leaving transactions unrolled.

Graceful Shutdown

Spring Boot 2.3 adds built‑in support for graceful shutdown for all embedded servers (Jetty, Reactor Netty, Tomcat, Undertow) and both servlet‑based and reactive web applications.

To enable it, add the following property: server.shutdown=graceful When this property is set, the server stops accepting new requests and waits for a configurable buffer period for active requests to complete.

Configuration Experience

The enum that represents the shutdown mode is defined as:

/**
 * Configuration for shutting down a {@link WebServer}.
 *
 * @author Andy Wilkinson
 * @since 2.3.0
 */
public enum Shutdown {
    /**
     * Graceful shutdown (bounded).
     */
    GRACEFUL,

    /**
     * Immediate shutdown.
     */
    IMMEDIATE;
}

Timeout‑per‑shutdown‑phase Configuration

The default timeout is 30 seconds; after this period the application will stop even if some requests are still running, so the value should be tuned according to the workload.

Effect Demonstration

1. Send a request to the server.

2. Issue a shutdown command.

3. The server receives the shutdown signal and logs the following:

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

4. The in‑flight request finishes and the client receives the response.

Related Knowledge

Using kill -2 (SIGINT) triggers Java's ShutdownHook and allows graceful shutdown, whereas kill -9 (SIGKILL) terminates the process abruptly without invoking the hook.

Example of a shutdown hook registration:

//ApplicationContext
@Override
public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        // No shutdown hook registered yet.
        this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
            @Override
            public void run() {
                synchronized (startupShutdownMonitor) {
                    doClose();
                }
            }
        };
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}

Another way to trigger graceful shutdown is via the Actuator endpoint:

@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();
    }
}

Container‑Specific Behaviors

Web Container

Behavior

Tomcat 9.0.33+

Stops accepting new requests; client requests wait until timeout.

Reactor Netty

Stops accepting new requests; client requests wait until timeout.

Undertow

Stops accepting new requests; new client requests receive HTTP 503 immediately.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend DevelopmentSpring BootWeb serverGraceful Shutdown
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.