1. Preface
How will ongoing requests be handled during the restart of voice social source code? Will the message being consumed be lost? Will asynchronous tasks be interrupted? Since these problems exist, can't our voice social source code be restarted? However, our voice social source code is constantly restarted with the version iteration. Why do these problems not appear? 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"; } }
2.1. 2 call request
2.1. 3 simulation restart
kill -2 application pid
2.1. 4 phenomenon
2.1. 5 Conclusion
During the execution of the request, the voice social source code is closed, and a prompt of inaccessibility appears
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? Yes, just add an elegant shutdown configuration in the voice social source code 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)
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 voice social source code is closed during the request execution, the received request will still be executed
2.2 message consumption
As mentioned in the preface, in the process of message consumption, if the voice social source code is closed, will the message be lost or put back into the message queue?
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); } }
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(); } } }
2.2. 3 call request
2.2. 4 before closing the application
2.2. 5 after closing the application
2.2. 6 Conclusion
In the process of message consumption, turn off the voice social source code, and 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; } }
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..."); }); } }
2.3. 3 call request
2.3. 4 simulation restart
kill -2 application pid
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)
2.3. 6. Modify thread pool configuration
Add the following configuration to the thread pool configuration:
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); threadPoolTaskExecutor.setAwaitTerminationSeconds(120);
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...
2.3. 8 conclusion
Use the thread pool to execute asynchronous tasks. Tasks cannot be completed without adding configurations. Tasks can still be completed with adding configurations.
3. Summary
In order to ensure that tasks can still be executed and completed during the restart of voice social source code, you need to turn on the graceful shutdown configuration and add the waiting task execution completion and waiting time configuration to the thread pool