分布式定时任务系列4:任务执行引擎设计续

  • Post author:
  • Post category:其他





分布式定时任务系列3:任务执行引擎设计



https://blog.csdn.net/weigeshikebi/article/details/123145716?spm=1001.2014.3001.5502



在前面一节讨论中,设想基于xxl-job包装一个业务执行引擎出来,达到以下几个目的:

  • 并发问题

  • 重试机制

  • 统一的编程模型

  • 充分利用分布式系统的能力

系统设计

根据上面的几点,这节就想办法动手实现一个出来。

DB存储

由于目的是先把架子搭起来,而不用考虑其它性能方面,所以选用DB进行存储。初步的表设计如下

表主要字段解释如下

字段 类型 说明
task_type int 这个字段用于区分不同的业务/功能,比如短信发送,日终处理,权限清理等
sub_type int 这个字段的目的,是在同一个task_type下,如果有多个步骤都要进行定时任务处理,比如短信发送时:捞取符合条件的待发送账户,余额结算,短信发送等
task_status int 任务状态,表示任务的执行过程,比如:INIT,PROCESSING,FAIL,SUCCESS等
flow_id string 用来跟踪同一个task_type下,多个sub_type的执行过程的辅助字段

类图

对于异步任务来说, 使用者理论上只关心业务逻辑,所以要尽量只关注业务代码,而其它的都交给引擎去处理。所以最好是提供一个接口,让使用者来实现业务逻辑

  • Task接口是任务接口,任何一个业务处理都需要实现这个接口:比如MsgTaskImpl,BalanceTaskImpl等
  • MsgTaskImpl,BalanceTaskImpl是具体的业务实现,如果需要使用异步任务引擎,需要实现Task接口
  • TaskEngine是异步任务的入口,也是引擎被刺的核心类,里面有个execute方法,业务处理调用此方法驱动任务执行
  • TaskFactory是任务的工厂类,维护任务类型与任务实现之间的关系:当注册一个任务时,调用register方法设置到内部的一个Map变量,TaskEngine执行时,通过getByType获取对应的task实现执行,也就做到动态扩展
  • TaskStatusEnum,是任务的状态,任务是由业务产生,初始状态为INIT,被引擎执行之后变成PROCESSING,执行完成后,根据结果变为终态:SUCCESS/FAIL
  • InitializingBean,Spring的实例化接口,用它来将task实现注册到TaskFactory中
  • JobHandler,里面配置异步任务的规则,@XxlJob注解对应xxl-job平台任务

执行流程图

现在来看下一个任务执行的整体顺序,假设是短信发送的业务

  • 业务系统产生异步任务,存储到DB,调用task引擎提供的接口
  • xxl-job定时任务触发,通过taskEngine扫描到对应的处理任务
  • 将任务从INIT更新为PROCESSING,表示正在处理中
  • taskEngine根据taskType,subType从TaskFactory中获取对应的处理实例,执行对应的业务逻辑:业务逻辑由task实现的业务处理编写
  • 执行完成,更新任务状态为终态:如果成功为SUCCESS,失败为FAIL

并发的处理

这里要考虑并发的问题,即多台实例执行同一个任务时,只能有一个线程在执行,自然而然想到锁,对于分布式的情况,可以用分布式锁来控制,所以这里还需要依赖redis之类的做分布式锁

异常的处理

这里还要考虑,如果是业务处理发生异常,任务状态该怎么处理?直接更新为FAIL,是最简单且直接的处理,但是如果异常不是业务异常,是网络抖动之类的,是不是应该考虑兼容,做到自动重试?所以这里面还要涉及到重试的处理

基于此,上面的类图,应该增加对redis的依赖

且最终和执行逻辑为



版权声明:本文为weigeshikebi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。