依赖quartz框架实现定时任务的动态配置
前言
当前项目中存在大量的定时任务,当前的定时任务方案存在以下缺点:一、与业务工程耦合度太高,manager中的业务定时类越来多,二、不能集中统一配置,分散的定时表达式配置在不同的配置文件中,三、不能临时暂停、恢复定时任务,四、修改定时配置,需要重启manager。而且后续随着项目数量的增加,以及交易设计的异步化,都需要增加更多的定时任务。quartz框架比较成熟,有完整的api支持动态配置。
实现方案
任务的配置
之前纠结过是在配置文件中配置刷入到redis,还是在oracle中配置。配置文件的好处是可以和源码一起做版本管理,且redis的读取速度够快。但后来考虑了一下,定时任务的配置可以考虑成业务交易数据,版本管理的意义不大,而且任务是在系统启动后立即完成加载,基本不需要实时读取,读取速度的快慢也无所谓了,所以最后选择放到oracle中管理。
动态任务配置表结构
- 任务名称、任务组、任务描述用来标识唯一的任务,说明任务的用途。任务名称是主键,保证唯一的前提下,命名应尽量能够清楚的表明任务的用途。任务组代表着任务的一个分类,命名使用任务所属的业务系统,如日切、交易检查-public,京东金融-oenjd,百度金融-openbd,公积金-paf等。任务描述使用汉字来辅助说明定时任务的用途。
- 任务表达式为quartz的定时表达式,通过管理端页面进行添加时,会使用quartz的表达式检查api进行表达式合法性检查,保证表达式格式正确。
- 执行类为被定时调度的具体Job,因为自定义了创建Job的工厂类,所以在Job中也可以注入spring中的实例对象。以后除了com.fxbank.cip.manager.task.job.EndOfDay在manager工程中负责进行日切作业外,还内置了com.fxbank.cip.manager.task.job.HttpPoster完成模拟esb客户端进行调度,业务定时任务执行类都应该配置成com.fxbank.cip.manager.task.job.HttpPoster,HttpPoster实际是一个ESB客户端,结合配置发起esb的标接通讯HTTP+JSON。与表达式一样,通过管理端添加的时候,会使用Class.forname检查配置的class是否准确。
- 发送URL、服务代码、服务场景、发送内容配置定时任务的触发参数。发送URL为web工程发布给esb调用的url地址(业务服务的A10地址),服务代码、场景码对应esb报文头中的serviceId和sceneId,发送内容为esb的报文体。报文体配置固定为json数组,格式为:[{“NAME”:”aaa”,”VALUE”:”uuu”},{“NAME”:”abc”,”VALUE”:”aaa”},{“NAME”:”ccc”,”VALUE”:”xxxx”}],数组内容可以随意扩展,如果没有报文体,则不配置即可。
- 任务状态为启用状态时才会在工程启动中启动定时任务,状态为关闭的任务不会随着项目启动。
- 更新日期和更新时间在新增和编辑定时任务时会进行更新。
动态任务配置
- 新增:登记SYS_TASK,如果状态为启用,则启动定时任务;
- 启动:将定时状态从停用改为启用,并添加并启动定时任务;
- 关闭:将定时状态从启用改为停用,并移除定时任务;
- 暂停:数据库中任务配置不变,暂停定时任务;
- 恢复:数据库中任务配置不变,将任务从暂停变为正常状态;
- 触发:定时任务必须为启用状态,可以触发一次处于正常、暂停状态的定时任务;
- 编辑:编辑定时任务,任务名称、任务组不可修改;
- 删除:只可以删除处于关闭状态的定时任务,从SYS_TASk中删除任务配置。
升级和新建定时任务
今后业务系统的相关定时任务都应放到对应业务系统的web工程中,在web工程的trade下新建job目录,放对应系统的定时任务类。定时类的写法与普通esb交易相同,定时任务类的请求和应答model例子为manager的com.fxbank.cip.manager.task.job包下的REQ_90000000001.REP_90000000001.java。例子对应的定时任务serviceId、sceneId为900000000、01。
定时任务类型中日期、时间分别从ESB的头中的tran_date和tran_timestamp中获取。