令人惊奇的是,仍然没有基于CronExpression获取上一次触发时间的石英方法...
如何获取上一次触发时间?
如果您正在操作基本的CRON,例如0 0 0 * * ?
(每天凌晨00:00:00),则可以使用João Neves的解决方案(使用com.cronutils.model.time.ExecutionTime)。
否则,如果您正在操作复杂的CRON,例如0 30 11 ? * MON,THU *
,它将无法正常工作。您将获得随机结果(我得到了星期三...)。
编辑:我进行了其他测试,最新版本效果更好(之前的测试是使用版本<3.1.6进行的)。注意:如果您要使用版本>3.1.6,则需要Java 8。
您可以使用的解决方案是在触发作业时存储它。
如何验证作业已被触发?
我找到的解决方案是使用Quartz(CronExpression)中的getNextValidTimeAfter
。这个方法很好用。
你会问我为什么要寻找上一个有效时间!你是对的,请给我一秒钟!
假设我们有一个每月一次的CRON(0 0 16 1 * ? = 每月1日下午4:00:00),我们想每天检查前一次执行是否成功。
您需要在每次执行时存储getNextValidTime,并将此日期与今天的日期进行比较。例如(格式DD/MM/YYYY):
• 01/01/2019 → 作业已触发,我们存储下一个触发时间(称其为nextFireTime
):
CronExpression trigger = new CronExpression("0 0 16 1 * ?");
Date nextFireTime = trigger.getNextValidTimeAfter(new Date());
• 02/01/2019 → 验证日期:02/01/2019 < 01/02/2019 通过
...
• 01/02/2019 → 假设服务器宕机,任务未被触发。
• 02/02/2019 → 服务器开启,日期验证:02/02/2019 > 01/02/2019 不行!
→ 我们知道之前的触发时间没有起作用。现在你可以按照自己的意愿去做(触发任务并存储新的下一次触发时间)。
另一个可能会引起您兴趣的选项,请参见MISFIRE_INSTRUCTION_FIRE_NOW。
调度程序发现触发器错过时,作业将立即执行。这是明智的策略。例如:您已经在凌晨2点安排了一些系统清理工作。不幸的是,应用程序由于维护而在那个时间段内关闭,并在凌晨3点重新启动。因此,触发器失效,调度程序试图通过在尽可能快的时间(即凌晨3点)运行它来挽救局面。
来源(https://dzone.com/articles/quartz-scheduler-misfire)
e.g.:
Trigger trigger = newTrigger().
withSchedule(
cronSchedule("0 0 9-17 ? * MON-FRI").
withMisfireHandlingInstructionFireAndProceed()
).
build();
官方文档:
https://www.quartz-scheduler.org/api/2.1.7/org/quartz/CronTrigger.html