Today I am going to discuss a simple but an essential practice of running Spring Boot Application on Production Environment. I hardly noticed that developers are aware of this. Today we will learn how to stop Spring Boot Applications safely and gracefully without failing any currently processing request or without breaking ongoing transactions.
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.
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("/products")
public ResponseEntity<Map<String, Object>> addProduct(@RequestBody Product product) {
log.info("Received request to add new product");
productService.add(product);
log.info("Successfully added new product");
return ResponseEntity.created(uri).body(
Map.of(
"status", 201,
"message": "Product added successfully",
"data", product
)
);
}
Now let’s check the log
11:04:44|INFO | o.s.w.s.DispatcherServlet:537 - Completed initialization in 33 ms
11:04:44|INFO | c.a.s.t.s.w.StudentController:38 - Received request to add new product
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
Yes!!! This is all you need
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.
Now let’s run the same previous example from above and check the log
14:14:57|INFO | c.a.s.t.s.w.StudentController:38 - Received request to add new product
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 product
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.
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 when graceful shutdown is enabled. However, we can configure it by using application properties.
spring.lifecycle.timeout-per-shutdown-phase=10s
Like any other Spring properties, we can also externalize this property. In other words the property can be passed as an environment variable, or run command etc.