In short, it is to send a stop command to the application process to ensure that the ongoing business operations are not affected, can continue to complete the processing of existing requests, but stop accepting new requests.

New feature in Spring Boot 2.3 graceful stop, Graceful stops are currently supported by the four embedded Web servers built into Spring Boot (Jetty, Reactor Netty, Tomcat, and Undertow) as well as reactive and servlet-based Web applications.

Let’s try it with the new version:

Spring Boot 2.3 Gracefully stops

First create a Spring Boot Web project, version 2.3.0.release, Spring Boot 2.3.0.release built-in Tomcat 9.0.35.

Then you need to add some configuration in application.yml to enable graceful stop:

# enable graceful stop Web container, default to IMMEDIATE: stop immediately
server:
  shutdown: graceful

# Maximum waiting time
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s
Copy the code

Among them, the smooth closing the built-in Web container for Tomcat (for example) the entrance of the code in the org. Springframework. Boot. Web. Embedded. Tomcat GracefulShutdown, The logic is to stop all new external requests first, and then process the requests received before closing. If you are interested, take a look.

The embedded Tomcat container smooth closure configuration is complete, so how to gracefully shut down the Spring container, you need to use the Actuator to shut down the Spring container.

Then add the actuator dependencies, which look like the following:

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

Then add some configurations to expose the shutdown interface of the actuator:

Expose the shutdown interface
management:
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        include: shutdown
Copy the code

It closed by a physical Spring container entry code in org. Springframework. Boot. Actuate. The context under the package ShutdownEndpoint class, The main thing is to execute the doClose() method to close and destroy the applicationContext, if you’re interested.

After configuration, create a WorkController class under the Controller package and have a work method to simulate complex business time-consuming processing process. The specific code is as follows:

@RestController
public class WorkController {

    @GetMapping("/work") public String work() throws InterruptedException {thread.sleep (10 * 1000L);return "success"; }}Copy the code

Then, we start the project, first with the Postman request processing business: http://localhost:8080/work

And call http://localhost:8080/actuator/shutdown at this time, you can perform gracefully stop and return the result as follows:

{
    "message": "Shutting down, bye..."
}
Copy the code

If at this time, a new request to http://localhost:8080/work, there will be no response:

Looking back at the first request, it returns the result: SUCCESS.

Some of the service logs are as follows:

The 23:05:15 2020-05-20. 102724-163 the INFO/Thread - 253 O.S.B.W.E.T omcat. GracefulShutdown: Commencing graceful shutdown. WaitingforActive requests to complete the 2020-05-20 23:05:15. 102724-287 the INFO/tomcat - shutdown O.S.B.W.E.T omcat. GracefulShutdown : Graceful shutdown complete 23:05:15 2020-05-20. 102724-295 the INFO/Thread - 253 O.S.S.C oncurrent. ThreadPoolTaskExecutor  : Shutting down ExecutorService'applicationTaskExecutor'
Copy the code

As you can also see from the logs, when the shutdown interface is called, it waits for the request to complete and then gracefully stops.

So far, the graceful shutdown of Spring Boot 2.3 has been explained, isn’t it very simple? How do I do this if I didn’t support graceful closing before?

Older versions of Spring Boot stop gracefully

Here is a solution offered by the Spring Boot developers in the GitHub issue:

Selection of Spring Boot version for 2.2.6. RELEASE, the first thing to realize TomcatConnectorCustomizer interface, this interface is a custom callback interface Connector:

@FunctionalInterface
public interface TomcatConnectorCustomizer {

	void customize(Connector connector);
}
Copy the code

In addition to customizing Connector behavior, implement the ApplicationListener

interface to listen for Spring container closure events, The current ApplicationContext executes the close() method so that we can close the Tomcat thread pool after the request is processed.

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

private static class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
    private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class);

    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) {
            try {
                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                threadPoolExecutor.shutdown();
                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(); }}}}Copy the code

With a custom Connector callback, you also need to add it to the embedded Tomcat container during startup and wait for the shutdown command to be listened on. The addConnectorCustomizers method can add custom Connector behavior to embedded Tomcat as follows:

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

At this point, the smooth closure of the built-in Tomcat container is complete, and the graceful closure of the Spring container has been described above and won’t be repeated again.

Through testing, you can also achieve the above elegant stop effect.

conclusion

This article mainly explains the graceful stop of Spring Boot 2.3 and older versions to avoid the situation that the forced stop will interrupt the business logic being processed, resulting in service exceptions.

In addition, the use of the Actuator should pay attention to security issues. For example, the use of the Actuator can introduce security dependencies, enable security restrictions and perform authentication, and configure a separate management port of the Actuator that is open only to the internal network.

In this paper, the complete code in a graceful shutdown – directory of https://github.com/wupeixuan/SpringBoot-Learn.

The best relationship is mutual achievement. The three links of watching, forwarding and leaving messages are the biggest motivation for my creation.

reference

Github.com/spring-proj…

Github.com/wupeixuan/S…