語音社交原始碼重啟,正在執行的任務會如何處理?

雲豹科技程式設計師發表於2021-12-14

1.前言

在語音社交原始碼重啟過程中,正在進行的請求會如何被處理?正在消費的訊息會不會丟失?非同步執行的任務會不會被中斷?既然存在這些問題,那我們的語音社交原始碼是不是就不能重啟?但是,我們的語音社交原始碼隨著版本迭代也在不斷重啟為什麼這些問題沒有出現呢?還是應用做了額外處理?帶著這些疑問,結合場景模擬,看看實際情況怎麼處理。

2. 場景

2.1 http請求
2.1.1 建立請求
@RestController
public class ShutDownController {
    @RequestMapping("shut/down")
    public String shutDown() throws InterruptedException {
        TimeUnit.SECONDS.sleep(20);
        return "hello";
    }
}
2.1.2 呼叫請求
2.1.3 模擬重啟
kill -2 應用pid
2.1.4 現象
語音社交原始碼重啟,正在執行的任務會如何處理?
2.1.5 結論
請求執行過程中,關閉語音社交原始碼出現無法訪問提示
2.1.6 開啟優雅關機
如上出現的現象對使用者來說很不友好,會造成使用者一臉懵逼,那麼有沒有什麼措施可以避免這種現象的出現呢?是否可以在應用關閉前執行完已經接受的請求,拒絕新的請求呢?答案可以的,只需要在語音社交原始碼配置檔案中新增優雅關機配置
server:
  shutdown: graceful # 設定優雅關閉,該功能在Spring Boot2.3版本中才有。注意:需要使用Kill -2 觸發來關閉應用,該命令會觸發shutdownHook
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s # 設定緩衝時間,注意需要帶上時間單位(該時間用於等待任務執行完成)
新增完配置後,再次執行2.1.2和2.1.3流程,就會看到如下效果
語音社交原始碼重啟,正在執行的任務會如何處理?
可以看到,即便在請求執行過程中關閉語音社交原始碼,已接收的請求依然會執行下去
2.2 訊息消費
在前言提到過,訊息消費過程中,關閉語音社交原始碼,訊息是會丟失還是會被重新放入訊息佇列中呢?
2.2.1 建立生產者
@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 建立消費者
@Component
@RabbitListener(queues = RabbitmqConfig.BUSINESS_QUEUE_NAME)
@Slf4j
public class BusinessConsumer {
    /**
     * 操作場景:
     * 1.通過RabbitmqApplication啟動類啟動應用程式
     * 2.呼叫/sendBusinessMessage介面傳送訊息
     * 3.RabbitMQ broker將訊息傳送給消費者
     * 4.消費者收到訊息後進行消費
     * 5.消費者消費訊息過程中,應用程式關閉,斷開channel,斷開connection,未ack的訊息會被重新放入broker中
     *
     * @param content 訊息內容
     * @param channel channel通道
     * @param message message物件
     */
    @RabbitHandler
    public void helloConsumer(String content, Channel channel, Message message) {
        log.info("business consumer receive message:{}", content);
        try {
            // 模擬業務執行耗時
            TimeUnit.SECONDS.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
2.2.3 呼叫請求
2.2.4 未關閉應用前
語音社交原始碼重啟,正在執行的任務會如何處理?
2.2.5 關閉應用後
語音社交原始碼重啟,正在執行的任務會如何處理?
2.2.6 結論訊息消費過程中,關閉語音社交原始碼,未ack的訊息會被重新放入訊息佇列中,以此來保證訊息一定會被消費
2.3 非同步任務
2.3.1 執行緒池配置
@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 非同步任務請求
@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 呼叫請求
2.3.4 模擬重啟
kill -2 應用pid
2.3.5 現象
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 修改執行緒池配置
線上程池配置中新增如下配置:
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskExecutor.setAwaitTerminationSeconds(120);
2.3.7 修改配置後現象
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 結論
使用執行緒池執行非同步任務,在沒有新增配置的情況下,任務無法執行完成,在新增配置的情況下,任務依然可以執行完成。

3. 總結

為了保證在語音社交原始碼重啟過程中任務仍然可以執行完成,需要開啟優雅關機配置並對執行緒池新增等待任務執行完成以及等待時間配置
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理 原文連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2847716/,如需轉載,請註明出處,否則將追究法律責任。

相關文章