Quartz Java恢复作业会执行多次

Quartz Java恢复作业会执行多次,java,scheduling,scheduled-tasks,quartz-scheduler,Java,Scheduling,Scheduled Tasks,Quartz Scheduler,对于我的应用程序,我创建作业并使用CronTriggers安排它们。每个作业只有一个触发器,并且作业名称和触发器名称相同。没有工作是共同的触发因素 现在,当我创建这样一个cron触发器时,“0/1****?”指示作业每秒钟执行一次,它工作得很好 当我第一次通过呼叫暂停作业时,问题出现了: scheduler.pauseJob(jobName, jobGroup); 然后在50秒后恢复作业: scheduler.resumeJob(jobName, jobGroup); 我看到的是,在这50秒

对于我的应用程序,我创建作业并使用CronTriggers安排它们。每个作业只有一个触发器,并且作业名称和触发器名称相同。没有工作是共同的触发因素

现在,当我创建这样一个cron触发器时,“0/1****?”指示作业每秒钟执行一次,它工作得很好

当我第一次通过呼叫暂停作业时,问题出现了:

scheduler.pauseJob(jobName, jobGroup);
然后在50秒后恢复作业:

scheduler.resumeJob(jobName, jobGroup);
我看到的是,在这50秒内,作业没有按要求执行。但是当我恢复工作的时候,我看到了50个同时执行的工作

我认为这是由于缺火指令的默认设置,但即使在创建时将触发器的缺火指令设置为:

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);

同样的事情也会发生。有人能提出解决方法吗?

如果暂停作业,触发器将继续触发,但执行将排队,直到作业恢复。这不是缺火触发器,因此该设置将无效


我认为,您想要做的是以编程方式禁用或删除cron触发器,而不是暂停作业。当您想要恢复时,请重新添加触发器。

通过记住
nextFireTime
来执行
CronTrigger
。创建触发器后,将初始化
nextFireTime
。每次触发作业时,
nextFireTime
都会更新。由于暂停时未触发作业,因此下一个FireTime保持“旧”。因此,在恢复作业后,触发器将在每个旧触发器时间返回

问题是,触发器不知道它正在暂停。要克服这一点,需要进行缺火处理。恢复作业后,将调用触发器的
updateAfterMisfire()
方法,以更正
nextFireTime
。但如果下一次上班时间与现在的差异小于。那么就永远不会调用该方法。此阈值的默认值为60000。因此,如果你的暂停时间超过60秒,一切都会很好

既然你有问题,我想不是 要解决此问题,您可以修改阈值或在
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;
    }
}
公共类PauseAwareContrigger扩展了CronTrigger{
//你需要的建设者到这里来
@凌驾
公共日期getNextFireTime(){
Date nextFireTime=super.getNextFireTime();
if(nextFireTime.getTime()
至少从1.6.5版开始(我指的是最早的quartz版本),调度器有一个pauseTrigger方法,它将名称/组作为参数。这意味着您不必拥有所使用的每种触发器类型的子类,也不必执行时髦的删除/插入技巧


这两个对我来说都很重要,因为1)我们的数据库有严格的不删除策略,2)我使用的自定义数据存储不支持触发器子类

您可以在org.quartz.impl.jdbcjobstore.JobStoreSupport#resumeTrigger(连接连接,触发器键)中添加这些代码

OperableTrigger=getDelegate()。选择触发器(连接,键)
if(trigger.getNextFireTime().getTime()

trigger.setNextFireTime(trigger.getFireTimeAfter(null));

}

jobdailjob=retrieveJob(conn,status.getJobKey())
storeTrigger(conn,trigger,job,true,status.getStatus(),false,false)


使用这些代码,当暂停的作业被恢复时,它不会立即被触发。另一方面,它将在下一个触发时间被触发,该时间由恢复时间计算。

pauseJob方法的javadoc说“暂停具有给定名称的JobDetail-暂停其所有当前触发器。”因此我猜测触发器正在暂停。触发器本身也没有暂停方法。或者任何类似的东西。仅仅从作业中移除触发器并重新插入它是暂停作业的唯一选项吗?我的意思是,这是一个非常琐碎的事情,希望您的调度程序去做。为什么它不能简单地工作?嗯,很好。我发现,对于石英,尝试各种事情直到某件事情起作用是最有效的方法,因为它并不总是按照锡上所说的去做。这是非常令人沮丧的,因为也没有简单的方法从工作中移除触发器。我能做一份没有触发器的工作吗?如果是,怎么做?有什么想法吗?我开始对这个失去耐心了,我已经试了好几个小时:)非常感谢:)这很有魅力。像暂停工作这样简单的任务会产生这样的问题,这似乎很奇怪。