IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 应用重启正在执行的任务会如何处理? -> 正文阅读

[Java知识库]应用重启正在执行的任务会如何处理?

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 调用请求

http://localhost:8080/shut/down

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.22.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 调用请求

http://localhost:8080/sendBusinessMessage

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 调用请求

http://localhost:8080/async/task

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. 总结

为了保证在应用程序重启过程中任务仍然可以执行完成,需要开启优雅关机配置并对线程池添加等待任务执行完成以及等待时间配置


?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-11 15:35:19  更:2021-12-11 15:36:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:27:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码