1)任务 Job
我们想要调度的任务都必须实现 org.quartz.job 接口,然后实现接口中定义的 execute( ) 方法即可
2)触发器 Trigger
Trigger 作为执行任务的调度器。我们如果想要凌晨1点执行备份数据的任务,那么 Trigger 就会设置凌晨1点执行该任务。其中 Trigger 又分为 SimpleTrigger 和 CronTrigger 两种
3)调度器 Scheduler
Scheduler 为任务的调度器,它会将任务 Job 及触发器 Trigger 整合起来,负责基于 Trigger 设定的时间来执行 Job
这是一个Quartz的一个大体架构,由Scheduler作为调度中心,管理Trigger,多个Trigger可以与多个Job进行关联,是一个多对多的关系,Trigger内部分为Simple Trigger和一个Cron Trigger,目前我们用的是后者,使用更便捷,更易于管理
踩的坑
1、Job延迟或不执行
在服务切换第一天,在上线之后用户隐隐有订单反应慢,或者更新不及时的状况,也是没有太注意(粗略观察控制台,看到job有在正常执行),到后面用户反应有的程序已经死掉没有跑了。收到紧急反馈后马上去看了数据库job执行的日志(项目有记录每个job的执行时间、结束时间、耗时),发现有的job确实很久没跑了,或者隔三差五但没有按照预定设置cron的时间进行,第一时间没有定位问题,先把线上控制台日志备份后,马上回滚到旧的定时服务,切换后系统恢复正常。暂时定位确定的是新定时服务内部的问题,隔天上班开始分析备份的备份下来的日志,发现job的执行线程ID,都是在1 ~ 10之间,第一猜想是Job服务数量太多,导致线程不够,job还在排队执行。因为线程ID是在1~10之间,可以猜测Quartz底层使用的是线程池执行任务的,只需要将这个线程池线程数量扩大即可解决,通过查阅并配置后,将配置线程数量调整至50,重新上线测试。
2、线程池数量配置失效
在最开始发现job延迟或不执行,最后调整线程数量至50。
上线后开始一切正常,执行一段时间后,还是同样的问题,用户反馈任务执行不及时,也是马上下载线上控制台日志后回滚至旧服务,经过观察后线程ID仍然在1~10之间循环,顿时疑惑了,查看Quartz源码后,也是没问题的,照理会去读取这个配置文件没有错,但还是失效了,百度google后仍然百思不得其解,最后在观察代码的时候突然看到了这个Scheduler是使用的@Autowired注解来配置的(Scheduler是任务调度器,线程池也是由Scheduler来使用的,也就是说问题出在这个Scheduler的配置上),猜想会不会是Spring在创建这个Scheduler的时候并没有读取到我的配置或者说被覆盖了,粗略看了Spring装在Scheduler的代码后,发现基于Autowired注解注入的Scheduler是被Spring经过一层封装的,最后在配置文件上加伤Spring的前缀就可以了。
3、还是服务阻塞
经过上一个坑之后,线程数量的问题完美解决了,但是又出现了一个新的问题,还是有线程被阻塞住没有执行,看了线上控制台日志后,发现线程ID是在正常1 - 100之间循环的,也就证明线程是正常的,但还是会有线程阻塞,第一时间想到的是Http请求超时,连接没有释放,方法也对应着没有结束,而且在调度页面也将这个job改成了异步(不会管他有没有执行完,时间到就执行下一轮),索性就将所有的Http调用加上超时时间,上线后恢复正常运行。
原来的定时服务没有出现这种问题是因为,之前用的Hutool的一个cron工具包进行调度,底层没有用线程池化技术,也就是差不多每个线程都是new Thread().start()执行,由于Quartz使用的是线程池,就会有线程阻塞的问题。