我在 Spring 下使用 Quartz,由 jdbc 作业存储支持,并且我试图让它"现在"触发作业:
Trigger adHocTrigger = TriggerBuilder.newTrigger().withIdentity(adHocTriggerKey).forJob(jobKey).startNow().build();
quartzScheduler.scheduleJob(adHocTrigger); //now
默认情况下,此调用与作业实际开始执行时间之间的测量延迟为 ~30 秒。 下面是一个示例作业,用于测量我使用的一次性触发延迟:
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Trigger trigger = context.getTrigger();
if (!trigger.mayFireAgain()) {
//its a one-off, compute latency
long latency = System.currentTimeMillis() - trigger.getFinalFireTime().getTime();
logger.info("firing latency is {} millis",latency);
}
}
阅读文档后,我发现延迟的原因是"org.quartz.scheduler.idleWaitTime"配置参数(基本上是作业存储轮询频率?),可以配置为低至 1000 millis(此时 im 获得的延迟约为 900 毫秒)。
我知道将其设置得这么低可能会导致数据库抖动(im 使用 jdbc 作业存储),因此不建议这样做,但是有没有办法在不诉诸此的情况下实现低延迟?
是否没有可选的配置属性会导致"立即触发"实际执行?
在不降低 idleWaitTime 的情况下解决此问题的一种方法是稍微修改 QuartzScheduler 以支持事务。我不使用Spring,所以我不知道那里会是什么样子,但这是基本的想法。
class TransactionAwareScheduler extends QuartzScheduler {
@Override
protected void notifySchedulerThread(long candidateNewNextFireTime) {
if (insideTransaction) {
transaction.addCommitHook(() -> {
super.notifySchedulerThread(candidateNewNextFireTime);
});
}
} else {
super.notifySchedulerThread(candidateNewNextFireTime);
}
}
它为我们完全解决了这个问题。
文档说"triggerJob"将立即触发作业。检查这是否满足您的要求。
quartzScheduler.triggerJob(jobKey);