Graceful Shutdown in Spring Boot 2.3 and Earlier Versions

This article explains how to enable and use Spring Boot's graceful shutdown feature in version 2.3, including configuration of the embedded web server and Actuator, and also provides a custom solution for older Spring Boot releases to achieve smooth termination of ongoing requests.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Graceful Shutdown in Spring Boot 2.3 and Earlier Versions

Graceful shutdown means that after sending a stop command to an application process, ongoing business operations are allowed to finish while the application stops accepting new requests.

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

Spring Boot 2.3 Graceful Shutdown

Create a Spring Boot web project using version 2.3.0.RELEASE; the embedded Tomcat version is 9.0.35.

Add the following configuration to application.yml to enable graceful shutdown:

# Enable graceful shutdown (default is IMMEDIATE)
server:
  shutdown: graceful

# Maximum wait time
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

The core logic resides in

org.springframework.boot.web.embedded.tomcat.GracefulShutdown

, which first stops accepting new external requests and then processes the ones already received.

To shut down the Spring context gracefully, add the Actuator dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Expose the shutdown endpoint via configuration:

# Expose shutdown endpoint
management:
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        include: shutdown

The shutdown logic is implemented in org.springframework.boot.actuate.context.ShutdownEndpoint, which calls doClose() on the applicationContext.

Create a controller WorkController with a long‑running work() method to simulate a heavy business process:

@RestController
public class WorkController {

    @GetMapping("/work")
    public String work() throws InterruptedException {
        // Simulate complex business processing
        Thread.sleep(10 * 1000L);
        return "success";
    }
}

Start the application and invoke http://localhost:8080/work to begin processing, then call http://localhost:8080/actuator/shutdown. The shutdown response is:

{
    "message": "Shutting down, bye..."
}

New requests to /work are rejected while the in‑flight request completes, as shown by the service logs:

2020-05-20 23:05:15.163  INFO 102724 --- [     Thread-253] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2020-05-20 23:05:15.287  INFO 102724 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete
2020-05-20 23:05:15.295  INFO 102724 --- [     Thread-253] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

For older Spring Boot versions (e.g., 2.2.6.RELEASE) that lack built‑in graceful shutdown, a custom solution can be implemented by creating a TomcatConnectorCustomizer and an ApplicationListener<ContextClosedEvent> to pause the connector and shut down the thread pool gracefully:

@FunctionalInterface
public interface TomcatConnectorCustomizer {
    void customize(Connector connector);
}

@Bean
public GracefulShutdown gracefulShutdown() {
    return new GracefulShutdown();
}

private static class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
    private volatile Connector connector;
    @Override
    public void customize(Connector connector) { this.connector = connector; }
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        this.connector.pause();
        Executor executor = this.connector.getProtocolHandler().getExecutor();
        if (executor instanceof ThreadPoolExecutor) {
            ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
            threadPoolExecutor.shutdown();
            try {
                if (!threadPoolExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                    log.warn("Tomcat thread pool did not shut down gracefully within 30 seconds. Proceeding with forceful shutdown");
                }
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

Register the customizer with the embedded Tomcat factory:

@Bean
public ConfigurableServletWebServerFactory tomcatCustomizer() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers(gracefulShutdown());
    return factory;
}

Both approaches ensure that ongoing requests finish before the application stops, preventing abrupt termination and potential business errors.

Summary

The article demonstrates how to configure graceful shutdown in Spring Boot 2.3 and earlier versions, using built‑in features and custom code, and highlights security considerations when exposing the Actuator shutdown endpoint.

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 BootTomcatGraceful ShutdownActuator
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

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.