SpringTechnology

Shutdown Spring Boot Applications Gracefully

Learn How to stop Spring Boot Applications safely and gracefully without failing any currently processing request or without breaking ongoing transactions.

What is Graceful Shutdown?

The Graceful and the hard or Abrupt shutdown are the two methods of stopping an application. When an application is running, it performs a certain tasks or fulfil client requests. While doing so, it consumes various resources, make connections, persist data and / or handle transactions etc. We may want to stop a running application, in order to take it out of the system or to release a different version of the application, as part of the deployment. However, it is important to analyse and understand the consequences of abruptly stopping an application, and such consequences are purely based on the application functionality and its role in the overall system.

In order to explain in detail, the Graceful vs Hard or abrupt stopping an application is similar to stopping a computer. When we use the shutdown function of an operating system it prompts for any unsaved work or closing of some important applications. On contrast, when we do Hard shutdown, we lose any unsaved files, or unfinished works. Interestingly, the same logic applies to applications. Some applications are capable of resuming any unfinished tasks when they are restarted. Thus, such for such applications, abrupt stops doesn’t cause any harm. On the other hand, for some applications an abrupt shutdown may result in unwanted outcomes. For example, failure of a very large transactions, or opened resources, etc. Thus, while writing an application we should also pay attention to its shutdown procedure.

This tutorial assumes you can write your own Spring Boot Application. Visit How to Write Your Own Spring Boot REST Service in order to create a Spring Boot application from scratch.

Without Graceful Shutdown Enabled

When we stop a running application or a process the underlying operating system delivers a termination signal to the process. Without having enabled any mechanism for graceful shutdown a Spring Boot application will simply terminate as soon as it receives the signal.

In order to demonstrate this behaviour, let’s write Controller endpoint that takes significantly longer before returning. Alternatively, we can simply make the thread sleep for a considerable amount of time so that we get a chance to stop the application in the middle of the request processing.

@PostMapping("/students")
public void test(@RequestBody Student student) {
    log.info("Received request to add new student");
    studentService.addStudent(student);
    log.info("Successfully added new student");
}

Firstly, we will start the application and execute a request to this endpoint. After that, once the request starts processing we will try to stop the application. Finally, we will observe the logs.

11:04:44|INFO | o.s.w.s.DispatcherServlet:547 - Completed initialization in 33 ms
11:04:44|INFO | c.a.s.t.s.w.StudentController:38 - Received request to add new student
11:04:53|INFO | o.s.s.c.ThreadPoolTaskExecutor:218 - Shutting down ExecutorService 'applicationTaskExecutor'
11:04:53|INFO | c.z.h.HikariDataSource:350 - HikariPool-1 - Shutdown initiated...
11:04:53|INFO | c.z.h.HikariDataSource:352 - HikariPool-1 - Shutdown completed.

The logs indicates that before the POST request is completed, the application shutdown was attempted. Also, from the logs it is clear that the application stopped suddenly without waiting for the request to finish.

With Graceful Shutdown Enabled

Spring Boot supports auto configurable graceful shutdown, which is very easy to configure. Next config snippet shows, how to enable graceful shutdowns in Spring Boot.Yaml file

server:
  shutdown: graceful

Or, properties file.

server.shutdown=graceful

Having this enabled, Spring Boot will wait for the current requests to complete before closing down the Application Context fully. Also, during the shutdown phase it will stop accepting new requests. All of the Spring Boot’s embedded servers support graceful termination. However, the way of rejecting new requests may vary based on he individual server implementations. In oder to demonstrate the graceful shutdown we will cover a scenario of an ongoing HTTP request as well as a JMS Listener.

Http Request

This section demonstrates how to allow currently running HTTP requests to finish before stopping Spring Boot Application. Now that we have enabled the graceful shutdown, we will rerun the controller endpoint and try to stop the application before the request finishes.

@PostMapping("/students")
public void test(@RequestBody Student student) {
    log.info("Received request to add new student");
    studentService.addStudent(student);
    log.info("Successfully added new student");
}

Let’s execute the POST endpoint, and immediately stop the application

14:14:57|INFO | c.a.s.t.s.w.StudentController:38 - Received request to add new student
14:14:58|INFO | o.s.b.w.e.t.GracefulShutdown:53 - Commencing graceful shutdown. Waiting for active requests to complete
14:15:07|INFO | c.a.s.t.s.w.StudentController:40 - Successfully added new student
14:15:07|INFO | o.s.b.w.e.t.GracefulShutdown:78 - Graceful shutdown complete
14:15:07|INFO | o.s.s.c.ThreadPoolTaskExecutor:218 - Shutting down ExecutorService 'applicationTaskExecutor'
14:15:07|INFO | c.z.h.HikariDataSource:350 - HikariPool-1 - Shutdown initiated...
14:15:07|INFO | c.z.h.HikariDataSource:352 - HikariPool-1 - Shutdown completed.

As seen in the logs the shutdown signal was received immediately after the endpoint was called. However, Spring Boot still allowed the request to finish before stopping the application context completely.

JMS Listener

Similarly, without graceful shutdown enabled any JMS listeners will also be killed upon application shutdown. Due to which, the JMS message will go back into the queue while its delivery count will still be increased. In this section, we will demonstrate how to allow current JMS message to be completely processed before a Spring Boot application is stopped.

Next is an example of a JMS Listener.

@JmsListener(destination = "queue/com.amitph.jms.example")
public void listenMessage(TextMessage textMessage) throws JMSException {
    log.info("Received a JMS Message");
    messageProcessor.process(textMessage.getText());
    log.info("Finished processing JMS Message");
}

Firstly, we will start the application and send a test message in the queue. After that, we will allow the listener to catch the message and stop the application immediately. Lastly, we will observe the logs.

14:27:28|INFO | c.a.s.t.s.Application:61 - Started Application in 9.708 seconds (JVM running for 10.059)
14:27:39|INFO | c.a.s.t.s.w.Listener:17 - Received a JMS Message
14:27:41|INFO | o.s.b.w.e.t.GracefulShutdown:53 - Commencing graceful shutdown. Waiting for active requests to complete
14:27:41|INFO | o.s.b.w.e.t.GracefulShutdown:78 - Graceful shutdown complete
14:27:49|INFO | c.a.s.t.s.w.Listener:19 - Finished processing JMS Message
14:27:49|INFO | o.s.s.c.ThreadPoolTaskExecutor:218 - Shutting down ExecutorService 'applicationTaskExecutor'
14:27:49|INFO | c.z.h.HikariDataSource:350 - HikariPool-1 - Shutdown initiated...
14:27:49|INFO | c.z.h.HikariDataSource:352 - HikariPool-1 - Shutdown completed.

As it is seen in the logs, the graceful shutdown was commenced right after the shutdown. However, Spring Boot allowed the listener to finish before stopping the application completely.

Graceful Shutdown Timeout

During a graceful shutdown Spring Boot allows some grace period to the application to finish all the current requests or processes. Once, the grace period is over the unfinished processes or requests are just killed. By default, Spring Boot allows a 30 seconds graceful shutdown timeout. However, we can configure it by using application properties or yaml file.

Yaml file.

spring:
  lifecycle:
    timeout-per-shutdown-phase: "10s"

Or, properties file

spring.lifecycle.timeout-per-shutdown-phase=10s

Like any other Spring properties, we can also externalise this property. In other words the property can be passed as an environment variable, or run command etc.

Summary

In this quick tutorial, we learned How to enable graceful shutdowns in Spring Boot applications. Having enabled graceful shutdown, Spring Boot allows the application to finish any ongoing request or process before stopping the application completely. Moreover, it prevents any new request from reaching to the application. Also, Spring Boot allows default grace period of 30 seconds for ongoing requests to finish. However, we can change this setting to specify a custom timeout value or grace period.

For more on Spring & Spring Boot, please visit Spring Tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *