Learn How to stop Spring Boot Applications safely and gracefully without failing any currently processing request or breaking ongoing transactions.
Tutorial Contents
What is a Graceful Shutdown?
The Graceful and the hard or Abrupt shutdown are the two methods of stopping an application. When an application runs, it performs specific tasks or processes client requests. While doing so, it consumes various resources, makes connections, persists data, handles transactions, etc. We may want to stop a running application to take it out of the system or release a different version of the application as part of the deployment. However, analyzing and understanding the consequences of abruptly stopping an application is essential. Such consequences are purely based on the application functionality and its role in the overall system.
To explain in detail, the Graceful vs Hard or abrupt stopping of 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 critical applications. In contrast, when we do a 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, for such applications, abrupt stops don’t cause any harm.
On the other hand, for some applications, an abrupt shutdown may result in unwanted outcomes—for example, failure of huge transactions or opened resources, etc. Thus, we should consider and plan for its shutdown procedure while writing an application.
This tutorial assumes you can write your Spring Boot Application. Please visit the How to Write Your Own Spring Boot REST Service 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 enabling any mechanism for graceful shutdown, a Spring Boot application will terminate as soon as it receives the signal.
To demonstrate this behaviour, let’s write a Controller endpoint that takes significantly longer before returning. Alternatively, we can 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");
}
Code language: Java (java)
Firstly, we will start the application and execute a request to this endpoint. After that, once the request begins 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.
Code language: plaintext (plaintext)
The logs indicate that the application shutdown was attempted before the POST request was completed. 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. The following config snippet shows how to enable graceful shutdowns in Spring Boot Yaml file.
server:
shutdown: graceful
Code language: YAML (yaml)
Or properties file.
server.shutdown=graceful
Code language: Properties (properties)
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 Spring Boot’s embedded servers support graceful termination. However, the way of rejecting new requests may vary based on the individual server implementations. To demonstrate the graceful shutdown, we will cover a scenario of an ongoing HTTP request and 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");
}
Code language: Java (java)
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.
Code language: plaintext (plaintext)
The logs show that the shutdown signal was received directly after the endpoint was called. However, Spring Boot allowed the request to finish before quitting the application context altogether.
JMS Listener
Similarly, without a graceful shutdown enabled, any JMS listeners will also be killed upon application shutdown. Due to this, the JMS message will go back into the queue while its delivery count will still be increased. This section will demonstrate allowing the current JMS message to be processed entirely 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");
}
Code language: Java (java)
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.
Code language: plaintext (plaintext)
As seen in the logs, the graceful shutdown 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 for 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-second graceful shutdown timeout. However, we can configure it by using application properties or YAML files.
Yaml file.
spring:
lifecycle:
timeout-per-shutdown-phase: "10s"
Code language: YAML (yaml)
Or, properties file
spring.lifecycle.timeout-per-shutdown-phase=10s
Code language: Properties (properties)
Like any other Spring property, we can also externalize this property. In other words, the property can be passed as an environment variable, 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 the application. Also, Spring Boot allows a 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.