AutoJob动态任务调度框架
AutoJob是一款轻量级任务调度框架,具有分布式、全异步、易拓展、易集成等特点,提供多种任务调度模式和多种任务类型。配置丰富、拓展方便、使用简单、代码侵入性低。
版本更新
2022-11-22: 初版0.9.1
2022-12-9: 0.9.2
优化API。
核心调度模块停止使用缓存时间戳,解决时间精度低的问题。
重构注解调度器。
重构执行器池,新增基于时间动态调整的线程池封装TimerThreadPoolExecutorHelper
。
修改已知BUG。
调整项目结构。
2022-12-26: 新增Rest接口:链接: https://www.apifox.cn/apidoc/shared-05120000-4d19-4c75-a7f6-dc56105972cb 访问密码 : autojob
2022-12-27: 优化子任务处理逻辑,新增任务MissFire事件
2022-12-29: 增加多数据库适配,目前支持mysql,postresql
2023-1-3:
优化重试机制,每个任务可单独配置重试逻辑
优化邮件报警机制,每个任务可单独配置邮箱
新增任务重试事件TaskRetryEvent
调度记录表新增is_retry
属性,表明该条调度记录是否是由于异常进行重试的调度记录
其他已知BUG
2023-3-14: 0.9.3
内置RPC框架编解码器改为使用ProtoStuff,简化API。
配置支持嵌套配置,内容可以通过VMOptions等给出,保护系统安全。
支持环境变量,便于在测试环境和生产环境切换。见:“四、环境变量”
2023-3-28: 0.9.4
对任务表进行拆分,目前拆分成aj_method_job和aj_script_job便于后期任务类型拓展。 注意0.9.4版本与之前版本的数据库结构不兼容
优化日志处理逻辑,从处理器私有处理线程到loop轮询,避免并发任务过多导致线程资源耗尽。
新增任务运行上下文、任务运行堆栈,便于故障恢复等。具体见“九、任务运行上下文;十一、所有配置”。
新增模板任务,更加优雅地开发任务。具体见:“十二、高级用法-注解任务开发的高级应用-@TemplateAutoJob
”。
2023-7-12: 0.9.5
解决日志存在的BUG:日志消息队列不清空的问题。 解决集群部署时重复启动的问题。 新增任务属性:executableMachines,用于指定执行机器,只有地址匹配的机器方可执行。数据库结构有变动(aj_method_job和aj_script_job新增executable_machines列),可以根据SQL脚本自行新增,不要直接执行脚本,否则会造成数据丢失。
2023-7-12: 0.9.6 最新
新增功能:
- 任务并发运行:同一个任务可以同时运行多个实例。
- 任务故障转移:重试策略新增故障转移策略,在开启集群模式时有效,异常的任务会选择一个“较好的”节点进行故障转移执行。
- 任务动态分片:在集群模式下支持分片任务,节点会自动感知当前集群节点数目,根据集群情况动态分片。
- 任务保存策略:支持不存在时保存、创建一个新的版本、存在则更新策略。
- 注解式脚本任务:可以直接在一个Java方法上使用
@ScriptJob
注解来定义一个脚本任务,支持动态命令行。 - 函数任务:可以非常简单的将一些业务逻辑交由AutoJob管理,AutoJob会为这些业务逻辑提供故障重试、过长中断、日志存储的功能。
其他性能优化和BUG解决。
更新说明:
本次更新涉及数据库结构变动,需要重新执行SQL脚本,请先备份数据。
一、背景
生活中,业务上我们会碰到很多有关作业调度的场景,如每周五十二点发放优惠券、或者每天凌晨进行缓存预热、亦或每月定期从第三方系统抽数等等,Spring和java目前也有原生的定时任务支持,但是其都存在一些弊病,如下:
- 不支持集群,未避免任务重复执行的问题
- 不支持生命周期的统一管理
- 不支持分片任务:处理有序数据时,多机器分片执行任务处理不同数据
- 不支持失败重试:出现异常任务终结,不能根据执行状态控制任务重新执行
- 不能很好的和企业系统集成,如不能很好的和企业系统前端集成以及不能很好的嵌入到后端服务
- 不支持动态调整:不重启服务情况下不能修改任务参数
- 无报警机制:任务失败之后没有报警通知(邮箱、短信)
- 无良好的执行日志和调度日志跟踪
基于原生定时任务的这些弊病,AutoJob就由此诞生,AutoJob为解决分布式作业调度提供了新的思路和解决方案。
二、特性
简单: 简单包括集成简单、开发简单和使用简单。
集成简单:框架能非常简单的集成到Spring项目和非Spring项目,得益于AutoJob不依赖于Spring容器环境和MyBatis环境,你无需为了使用该框架还得搭建一套Spring应用。
开发简单:AutoJob开发初衷就希望具有低代码侵入性和快速开发的特点,如下在任意一个类中,你只需要在某个需要调度的任务上加上注解,该任务就会被框架进行动态调度:
@AutoJob(attributes = "{'我爱你,心连心',12.5,12,true}", cronExpression = "5/7 * * * * ?")
public void formatAttributes(String string, Double decimal, Integer num, Boolean flag) {
//参数注入
AutoJobLogHelper logger = new AutoJobLogHelper();//使用框架内置的日志类
logger.setSlf4jProxy(log);//对Slf4j的log进行代理,日志输出将会使用Slf4j输出
logger.info("string={}", string);
logger.warn("decimal={}", decimal);
logger.debug("num={}", num);
logger.error("flag={}", flag);
//使用mapper
mapper.selectById(21312L);
//...
}
使用简单:使用该框架你无需关注太多的配置,整个框架的启动只需要一行代码,如下:
//配置任务扫描包路径
@AutoJobScan({"com.yourpackage"})
//处理器自动扫描
@AutoJobProcessorScan({"com.yourpackage"})
public class AutoJobMainApplication {
public static void main(String[] args) {
//框架启动
new AutoJobBootstrap(AutoJobMainApplication.class)
.build()
.run();
System.out.println("==================================>系统创建完成");
}
}
得益于良好的系统架构和编码设计,你的应用启动无需过多配置,只需要一行代码
动态: 框架提供API,支持任务的动态CURD操作,即时生效。
多数据库支持: 提供多类型数据库支持,目前支持MySQL、PostgreSQL、Oracle、DamengSQL,理论支持SQL标准的所有数据库。
任务依赖: 支持配置子任务,当父任务执行结束且执行成功后将会主动触发一次子任务的执行。
一致性: 框架使用DB乐观锁实现任务的一致性,在集群模式下,调度器在调度任务前都会尝试获取锁,获取锁成功后才会进行该任务的调度。
HA(新): 该框架支持去中心化的集群部署,集群节点通过RPC加密通信。集群节点之间会自动进行故障转移。
弹性增缩容(新): 支持节点的动态上下线,同时节点支持开启保护模式,防止恶劣的网络环境下节点脱离集群。
任务失败重试(新): 支持故障转移和本地重试。
完整的生命周期: 框架提供任务完整的生命周期事件,业务可捕捉并做对应的处理。
动态调度线程池: 框架使用自研的动态线程池,可灵活根据任务流量动态调整线程池核心线程和最大线程参数,节省系统线程资源,并且提供了默认的拒绝处理器,防止任务被missFire。
异步非阻塞的日志处理: 日志采用生产者消费者模型,基于自研的内存消息队列,任务方法作为日志的生产者,生产日志放入消息队列,框架启动对应的日志消费线程进行日志处理。
实时日志: 日志将会实时的进行保存,便于跟踪。
任务白名单: 提供任务白名单功能,只有在白名单中的任务才允许被注册和调度,保证系统安全。
可拓展的日志存储策略: 日志支持多种策略保存,如内存Cache、数据库等,可根据项目需要灵活增加保存策略,如Redis、文件等。
丰富的调度机制: 支持Cron like表达式,repeat-cycle调度、子任务触发、延迟触发等,得益于良好的编码设计,用户可非常简单的新增自定义调度器,如下:
/**
* 你的自定义调度器
* @Author Huang Yongxiang
* @Date 2022/08/18 14:56
*/
public class YourScheduler extends AbstractScheduler{
public YourScheduler(AutoJobTaskExecutorPool executorPool, IAutoJobRegister register, AutoJobConfigHolder configHolder) {
super(executorPool, register, configHolder);
}
//...调度逻辑
}
@AutoJobScan("com.example.autojob.job")
@AutoJobProcessorScan("com.example.autojob")
public class AutoJobMainApplication {
public static void main(String[] args) {
new AutoJobLauncherBuilder(AutoJobMainApplication.class)
.withAutoScanProcessor()
//配置你的调度器
.addScheduler(YourScheduler.class)
.build()
.run();
System.out.println("==================================>系统创建完成");
}
}
任务报警: 框架支持邮件报警,目前原生支持QQ邮箱、163邮箱、GMail等,同时也支持自定义的邮箱smtp服务器。
目前系统提供:任务失败报警、任务被拒报警、节点开启保护模式报警、节点关闭保护模式报警,当然用户也可非常简单的进行邮件报警的拓展。
丰富的任务入参: 框架支持基础的数据类型和对象类型的任务入参,如Boolean,String,Long,Integer,Double等类型,对于对象入参,框架默认使用JSON进行序列化入参。
良好的前端集成性: 框架提供相关API,用户可以灵活开发Restful接口接入到企业项目,无需额外占用一个进程或机器来单独运行调度中心。
内存任务: 框架提供DB任务和内存任务两种类型,DB任务持久化到数据库,声明周期在数据库内记录,内存任务除了日志,整个生命周期都在内存中完成,相比DB任务具有无锁、调度快速的特点。
脚本任务: 提供脚本任务的执行,如Python、Shell,SQL等。
动态分片(新): 集群模式下框架支持任务分片,多机运行。
全异步: 任务调度流程采用全异步实现,如异步调度、异步执行、异步日志等,有效对密集调度进行流量削峰,理论上支持任意时长任务的运行。