Spring Cloud Stream实战--异步任务的处理

本篇接上篇,用一个综合实例说明如何在在实际的项目中用MQ实现异步任务的处理。

一. 背景:

        生成报告是一个比较耗时的操作,  根据报告的复杂程度,通常需要10几秒到几十秒的时间。如果使用同步请求,就会导致调用者一直等待,造成系统拥塞和用户体验不好的情况。因此将此任务从业务角度拆解成异步任务去实现:

     1. 请求生成所需要报告的hashcode。

      2. 通过hashcode获取所需要的报告。

二. 代码设计架构实现

       设计架构的分解:

       1. 请求生成所需要报告的hashcode,发送给MQ

       2. MQ 收到消息,调用报告服务,生成报告,保存到数据库中

       3. 调用者通过重试机制从本服务数据库中获取报告, 而不是从远程

       4. 定时任务删除过期的报告

三.   代码实现  

     本实例的代码主要基于上篇MQ的基础之上,主要增加了数据库操作,重试机制以及定时任务删除操作。  

     整体结构图:

     

 

 

          1. MQ:主要重新配置了一个新的exchange( 略)

          2.  数据库操作 :使用JPA操作数据库(略)

          3. Retryer: 重试机制去数据库里面检查报告是否生成:

         

public abstract class AbstractRetryer<T, P> {
    private final Integer maxRetry;
    private final int sleep;

    public AbstractRetryer(Integer maxRetry, Integer sleep) {
        this.maxRetry = (maxRetry!=null)? maxRetry : 5;
        this.sleep = (sleep!=null)? sleep: 0;
    }

    protected abstract T retry(P params);

    public T init(P parmas){
        int tries = 0;
        while (tries < maxRetry){
           log.info("Retrying {}",tries );

           try {
               T value = retry(parmas);
               log.info("success retry {} times", tries);
               return value;
           } catch (Exception e){
               tries++;
               log.error("Error retring to call {}", e);
           }
           sleep();
       }
        return null;
    }

    private void sleep(){
        if (sleep<=0){
            return;
        }
        try {
            TimeUnit.SECONDS.sleep(sleep);
        } catch (InterruptedException e){
            log.error("error", e);
            Thread.currentThread().interrupt();
        }
    }
}

 

          4. Scheduler: 定时任务删除过期不用的报告;

 

public class ReportScheduler {
    @Value("${report.ttl}")
    private Integer ttl;

    private ReportRepository reportRepository;

    public ReportScheduler(ReportRepository reportRepository) {
        this.reportRepository = reportRepository;
    }

    @Scheduled(initialDelayString = "${report.initialDelay}", fixedDelayString = "${report.fixedDelay}")
    public void runTask(){
        List<String> hashcodes = reportRepository.getDocumentBefore(ttl);
        hashcodes.forEach(code ->{
            reportRepository.deleteById(code);
            log.info("delete the report {}", code);
        });
    }
}

 

posted @ 2022-10-01 12:31  梅花瘦  阅读(314)  评论(0)    收藏  举报