preface
Recently, some thoughts have been raised about system restart. How will ongoing requests be handled during system restart? Will the message being consumed be lost? Will asynchronous tasks be interrupted? Since these problems exist, can't our application be restarted? However, our application is constantly restarted with version iteration. Why do these problems not occur? Or did the application do additional processing? With these questions, combined with the scene simulation, see how to deal with the actual situation.
2. Scenario
2.1 http request
2.1. 1 create request
@RestController public class ShutDownController { @RequestMapping("shut/down") public String shutDown() throws InterruptedException { TimeUnit.SECONDS.sleep(20); return "hello"; } } Copy code
2.1. 2 call request
http://localhost:8080/shut/down
2.1. 3 simulation restart
kill -2 application pid Copy code
2.1. 4 phenomenon

2.1. 5 Conclusion
During the execution of the request, an inaccessible prompt appears when the application is closed
2.1. 6 turn on and turn off gracefully
The above phenomenon is very unfriendly to users and will cause users to look confused. Are there any measures to avoid this phenomenon? Can I execute accepted requests and reject new requests before the application closes? The answer is yes. You only need to add an elegant shutdown configuration in the configuration file
server: shutdown: graceful # Set elegant shutdown. This function is available in spring boot2 Only in version 3. Note: you need to use Kill -2 trigger to close the application. This command will trigger shutdown hook spring: lifecycle: timeout-per-shutdown-phase: 30s # Set the buffer time. Pay attention to the time unit (this time is used to wait for the completion of task execution) Copy code
After adding the configuration, execute 2.1.1 again 2 and 2.1 3 process, you will see the following effects

It can be seen that even if the application is closed during request execution, the received requests will still be executed
2.2 message consumption
As mentioned in the preface, will messages be lost or put back into the message queue when the application is closed during message consumption?
2.2. 1 create producer
@RestController public class RabbitMqController { @Autowired private RabbitTemplate rabbitTemplate; @GetMapping("/sendBusinessMessage") public void sendBusinessMessage() throws InterruptedException { rabbitTemplate.convertAndSend(RabbitmqConfig.BUSINESS_EXCHANGE, RabbitmqConfig.BUSINESS_ROUTING_KEY, "send message"); TimeUnit.SECONDS.sleep(10000); } } Copy code
2.2. 2 create a consumer
@Component @RabbitListener(queues = RabbitmqConfig.BUSINESS_QUEUE_NAME) @Slf4j public class BusinessConsumer { /** * Operation scenario: * 1.Start the application through the RabbitmqApplication startup class * 2.Call the / sendBusinessMessage interface to send a message * 3.RabbitMQ broker Send message to consumer * 4.Consumers consume after receiving the message * 5.When consumers consume messages, the application closes, the channel is disconnected, the connection is disconnected, and the messages without ack will be put back into the broker * * @param content Message content * @param channel channel passageway * @param message message object */ @RabbitHandler public void helloConsumer(String content, Channel channel, Message message) { log.info("business consumer receive message: {}", content); try { // Simulated business execution time TimeUnit.SECONDS.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } Copy code
2.2. 3 call request
http://localhost:8080/sendBusinessMessage
2.2. 4 before closing the application

2.2. 5 after closing the application

2.2. 6 Conclusion
In the process of message consumption, when the application is closed, the messages without ack will be put back into the message queue to ensure that the messages will be consumed
2.3 asynchronous tasks
2.3. 1. Configuration of route pool
@Component public class ThreadPoolConfig { @Bean public ThreadPoolTaskExecutor threadPoolTaskExecutor() { ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.setThreadNamePrefix("test-"); threadPoolTaskExecutor.setCorePoolSize(3); threadPoolTaskExecutor.setMaxPoolSize(3); threadPoolTaskExecutor.setQueueCapacity(100); return threadPoolTaskExecutor; } } Copy code
2.3. 2 asynchronous task request
@Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; @RequestMapping("async/task") public void asyncTask() throws InterruptedException { for (int i = 0; i < 10; i++) { threadPoolTaskExecutor.execute(() -> { try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(); } log.info("task execute complete..."); }); } } Copy code
2.3. 3 call request
http://localhost:8080/async/task
2.3. 4 simulation restart
kill -2 application pid Copy code
2.3. 5 phenomenon
Exception in thread "test-2" Exception in thread "test-1" Exception in thread "test-3" java.lang.RuntimeException at com.boot.example.ShutDownController.lambda$asyncTask$0(ShutDownController.java:37) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) java.lang.RuntimeException at com.boot.example.ShutDownController.lambda$asyncTask$0(ShutDownController.java:37) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) java.lang.RuntimeException at com.boot.example.ShutDownController.lambda$asyncTask$0(ShutDownController.java:37) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Copy code
2.3. 6. Modify thread pool configuration
Add the following configuration to the thread pool configuration:
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); threadPoolTaskExecutor.setAwaitTerminationSeconds(120); Copy code
2.3. 7 phenomena after modifying the configuration
2021-12-09 17:09:40.054 INFO 22383 --- [ test-1] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:09:40.055 INFO 22383 --- [ test-3] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:09:40.055 INFO 22383 --- [ test-2] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:09:50.059 INFO 22383 --- [ test-3] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:09:50.059 INFO 22383 --- [ test-1] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:09:50.060 INFO 22383 --- [ test-2] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:10:00.062 INFO 22383 --- [ test-2] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:10:00.062 INFO 22383 --- [ test-1] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:10:00.065 INFO 22383 --- [ test-3] com.boot.example.ShutDownController : task execute complete... 2021-12-09 17:10:10.066 INFO 22383 --- [ test-1] com.boot.example.ShutDownController : task execute complete... Copy code
2.3. 8 conclusion
Use the thread pool to execute asynchronous tasks. Without adding configuration, the task cannot be completed. When adding configuration, the task can still be completed.
3. Summary
In order to ensure that tasks can still be executed and completed during application restart, you need to enable graceful shutdown configuration and add wait task execution completion and wait time configuration to the thread pool