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.
Join the DZone community and get the full member experience.
Join For FreeWhat is a 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 certain tasks or processes client requests. While doing so, it consumes various resources, makes connections, persists data, and/or handles 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 analyze 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 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 important 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 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.
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 behavior, let’s write a 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 indicate 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. The 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 Spring Boot’s embedded servers support graceful termination. However, the way of rejecting new requests may vary based on the individual server implementations. In order 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 this, 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 the 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 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 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 property, we can also externalize 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 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.
Published at DZone with permission of Amit Phaltankar. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments