目录
- 1. 控制面的接口
- 2.手动触发任务
- 2. 定时任务的实现
1. 控制面的接口
服务端包含xxl-job的管理端,页面上的接口后端一系列的controller接口
appName
是一个核心概念,它是指执行器应用的名称,appName
是执行器的唯一标识
页面上的接口,对应这这里一系列的controller
2.手动触发任务
触发任务的接口为 /jobinfo/trigger
com.xxl.job.admin.controller.JobInfoController#triggerJob
触发任务执行的具体实现在 JobTriggerPoolHelper
,其中创建了一个快触发线程池 fastTriggerPool
和一个慢触发线程池 slowTriggerPool
,用于隔离较慢的响应节点。
在触发具体任务时,根据jobId判断,若触发该jobId的耗时在1分钟内有10次超过500ms,则该jobId使用 慢线程池执行,否则使用快线程池。
触发任务的关键方法为:com.xxl.job.admin.core.trigger.XxlJobTrigger#trigger
分片指的是任务分片广播执行的概念,当调度中心调度一个设置了分片参数的任务时,任务会被拆分成多个子任务(分片),每个分片会被分配一个唯一的序号(分片参数,通常从0开始)。
分片任务的处理主要还是在客户端,可参考如下示例
触发任务实际上就是发起一个http请求,但前中后会记录任务的执行结果、日志等信息,参考方法:com.xxl.job.admin.core.trigger.XxlJobTrigger#processTrigger
大体的步骤分为:
- 保存信息至log表
- 初始化TriggerParam数据
- 初始化客户端的ip地址(从grop中获取)
- 发起http调用(参考:
com.xxl.job.core.biz.client.ExecutorBizClient#run
) - 收集任务触发信息
- 将触发信息保存至log表中
2. 定时任务的实现
xxl-job中的定时任务是通过Cron表达式实现的,其具体的实现可参考 : com.xxl.job.admin.core.thread.JobScheduleHelper
对于定时任务的执行,其实现思路是:
- 线程异步轮询,计算job的下一次执行时间
- 线程异步轮询,计算当前时间窗口内需要执行的任务,并触发任务执行
根据Cron表达式计算任务的下一次执行时间: com.xxl.job.admin.core.thread.JobScheduleHelper#generateNextValidTime
在 JobScheduleHelper
维护了两个线程 scheduleThread
和 ringThread
,两者分工不同:
大体来讲,scheduleThread
是负责触发任务调度的线程,周期性地检查所有的任务计划(Cron表达式定义的任务),如果发现有任务到达执行时间,则将这些即将执行的任务放入到一个“时间轮”(ringData
字段,是是一个map结构),ringThread
会遍历时间轮,检查每个槽位上是否有任务需要执行,一旦发现,就立即进行处理(即发起调度)
但实际上,scheduleThread
的处理有很多细节:
scheduleThread
周期性从数据库中查询任务,查询之前,会基于数据库xxl_job_lock
表实现全局锁- 批量获取任务信息后,会便利判断当前job的下一次执行时间
- 若待执行任务时间早于(过期了)当前时间,且大于5秒,则进行MISFIRE触发
- 若待执行任务时间早于当前时间不超过5秒(过期了,但在窗口内),则进行CRON触发
由于scheduleThread周期性执行,为了处理周期间需要执行的任务,此处会判断,所触发任务后,下一次的待执行时间于当前时间相差不超过5秒,也会添加到时间轮中
- 若待执行时间晚于当前时间(还不需要执行),则将当前任务添加到时间轮中
- 更新数据库中的job信息(
trigger_last_time
、trigger_next_time
、trigger_status
) - 释放全局锁
- 若总耗时小于1000ms,则线程sleep一段时间