Quartz Java 恢复作业执行多次
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1933676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Quartz Java resuming a job executes it many times
提问by Savvas Dalkitsis
For my application I create jobs and schedule them with CronTriggers. Each job has only one trigger and both the job name and the trigger names are the same. No jobs share a trigger.
对于我的应用程序,我创建作业并使用 CronTriggers 安排它们。每个作业只有一个触发器,并且作业名称和触发器名称相同。没有作业共享触发器。
Now when i create a cron trigger like this "0/1 * * * * ?"which instructs the job to execute every second, it works just fine.
现在,当我创建一个像这样“0/1 * * * * ?”的 cron 触发器时 它指示作业每秒执行一次,它工作得很好。
The problem rises when I first pause the job by calling:
当我第一次通过调用暂停工作时,问题就出现了:
scheduler.pauseJob(jobName, jobGroup);
and then resuming the job after let's say 50 seconds with:
然后在让我们说 50 秒后恢复工作:
scheduler.resumeJob(jobName, jobGroup);
What I see is that for these 50 seconds the job did not execute as requested. But the moment I resume the job I see 50 executions of the job at the same time!!!
我看到的是,在这 50 秒内,作业没有按要求执行。但是在我恢复工作的那一刻,我看到同时执行了 50 个工作!!!
I thought that this was due to the default setting for the misfire instruction but even after setting the trigger's misfire instruction upon creation to this:
我认为这是由于失火指令的默认设置,但即使在创建时将触发器的失火指令设置为:
trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
The same thing happens. Can anyone suggest a way to fix this?
同样的事情发生。任何人都可以提出解决此问题的方法吗?
回答by Eduard Wirch
The CronTriggerworks by remembering the nextFireTime. After creating the trigger the nextFireTimeis initialized. Every time the job is triggered nextFireTimeis updated. Since the job is not triggered when paused nextFireTimeremains "old". So after you resume the job the trigger will return every old trigger time.
在CronTrigger通过记住的作品nextFireTime。创建触发器后,将对其nextFireTime进行初始化。每次触发作业时nextFireTime都会更新。由于暂停时未触发作业nextFireTime保持“旧”状态。因此,在您恢复工作后,触发器将返回每个旧的触发时间。
The problem is, the trigger doesn't know it is being paused. To overcome this there is this misfire handling. After resuming the jobs the trigger's updateAfterMisfire()method will be invoked which corrects the nextFireTime. But not if the difference between nextFireTimeand now is smaller than the misfireThreshold. Then the method is never called. This threshold's default value is 60,000. Thus if your pause period would be longer than 60s everything would be fine.
问题是,触发器不知道它正在暂停。为了克服这个问题,需要进行失火处理。恢复作业后,updateAfterMisfire()将调用触发器的方法来纠正nextFireTime. 但如果nextFireTime和 now之间的差异小于misfireThreshold ,则不会。然后该方法永远不会被调用。此阈值的默认值为 60,000。因此,如果您的暂停时间超过 60 秒,一切都会好起来的。
Since you have problems I assume it is not. ;)
To workaround this you can modify the threshold or use a simple wrapper around CronTrigger:
既然你有问题,我认为它不是。;) 要解决此问题,您可以修改阈值或使用简单的包装器CronTrigger:
public class PauseAwareCronTrigger extends CronTrigger {
// constructors you need go here
@Override
public Date getNextFireTime() {
Date nextFireTime = super.getNextFireTime();
if (nextFireTime.getTime() < System.currentTimeMillis()) {
// next fire time after now
nextFireTime = super.getFireTimeAfter(null);
super.setNextFireTime(nextFireTime);
}
return nextFireTime;
}
}
回答by skaffman
If you pause the job, the trigger will continue to fire, but the executions will queue up until the job is resumed. This isn't a misfiring trigger, so that setting will have no effect.
如果暂停作业,触发器将继续触发,但执行将排队等待作业恢复。这不是失火触发器,因此该设置将不起作用。
What you want to do, I think, is programmatically disable or remove the cron trigger, rather than pausing the job. When you want to resume, then re-add the trigger.
我认为您想要做的是以编程方式禁用或删除 cron 触发器,而不是暂停工作。当你想恢复时,再重新添加触发器。
回答by Michael Deardeuff
Since 1.6.5 at least (the earliest version of quartz at my fingertips), the scheduler has a pauseTrigger method that takes the name/group as parameters. This means you don't have to have a sub-class of every trigger type you use, nor do you have to do funky deletion/insertion tricks.
至少从 1.6.5 开始(我触手可及的最早版本的石英),调度程序有一个 pauseTrigger 方法,它将名称/组作为参数。这意味着您不必为您使用的每种触发器类型都创建一个子类,也不必使用时髦的删除/插入技巧。
Both of these are important to me because 1) our database has a strict no-deletes policy and 2) the custom datastore I use doesn't support trigger sub-classes.
这两个对我来说都很重要,因为 1) 我们的数据库有严格的禁止删除策略,2) 我使用的自定义数据存储不支持触发器子类。

