2011-11-23 60 views
5

我在Spring的Quartz中使用Quartz在每月的第一天午夜运行特定任务。我已经通过在本月的最后一天将服务器日期&的时间设置为11:59来测试该作业,启动服务器并观察任务运行时间为12:00,但我担心的情况是服务器(无论出于何种原因)可能不会在本月的第一天的午夜时间运行。运行错过的Quartz作业

我认为在Quartz中的失火处理会照顾到这一点,但也许我错了吗?

任何人都可以告诉我如何我可以处理这个?我真的不想创建一个每'x'秒/分钟/小时运行的作业,并检查是否需要运行该作业,如果我能避免它。

我也很好奇为什么我没有看到任何Quartz相关的日志记录信息,但这是次要问题。

下面是任务我的Spring配置:

<bean id="schedulerService" class="com.bah.pams.service.scheduler.SchedulerService"> 
    <property name="surveyResponseDao" ref="surveyResponseDao"/> 
    <property name="organizationDao" ref="organizationDao"/> 
</bean> 

<bean name="createSurveyResponsesJob" class="org.springframework.scheduling.quartz.JobDetailBean"> 
    <property name="jobClass" value="com.bah.pams.service.scheduler.jobs.CreateSurveyResponsesJob"/> 
    <property name="jobDataAsMap"> 
     <map> 
      <entry key="schedulerService" value-ref="schedulerService"/> 
     </map> 
    </property> 
</bean> 
<!-- Cron Trigger --> 
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
    <property name="jobDetail" ref="createSurveyResponsesJob"/> 
    <property name="cronExpression" value="0 0 0 1 * ? *"/> 
    <!--if the server is down at midnight on 1st of month, run this job as soon as it starts up next --> 
    <property name="misfireInstructionName" value="MISFIRE_INSTRUCTION_FIRE_ONCE_NOW"/> 
</bean> 

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 

    <property name="autoStartup" value="true"/> 

    <property name="quartzProperties"> 
     <props> 
      <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop> 
      <prop key="org.quartz.jobStore.misfireThreshold">60000</prop> 
     </props> 
    </property> 
    <property name="jobDetails"> 
     <list> 
      <ref bean="createSurveyResponsesJob"/> 
     </list> 
    </property> 

    <property name="triggers"> 
     <list> 
      <ref bean="cronTrigger"/> 
     </list> 
    </property> 
</bean> 

回答

2

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW是你提到的目的,如果您怀疑服务器(S)的关闭你一定要坚持你的工作了JVM内存(例如:通过使用JDBCJobStore而不是RAMJobStore)。

RAMJobStore快速且轻便,但当进程终止时,所有调度信息都会丢失。

http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigRAMJobStore

JDBCJobStore用于存储在关系数据库中的调度信息(作业,触发器和日历)。

http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJobStoreTX

希望它能帮助。

0

我也遇到了想要在服务器重启时运行最后一个计算作业的问题。

这是我找到的解决方案是回到触发器的一个时间间隔,并计算下一次发射时间。通过遍历所有触发器,可以确定触发器应该在过去触发的最近时间。


计算每个发射间隔:

Date nextFireTime = trigger.getNextFireTime(); 
Date subsequentFireTime = trigger.getFireTimeAfter(nextFireTime); 
long interval = subsequentFireTime.getTime() - nextFireTime.getTime(); 

查找下一个发射时间为一周时间,直到在过去的时间间隔:

Date previousPeriodTime = new Date(System.currentTimeMillis() - interval); 
Date previousFireTime = trigger.getFireTimeAfter(previousPeriodTime); 

我发现,如果你正在使用这可以防止你在过去要求火灾时间。要解决此我修改了启动时间,所​​以上面的代码变成:

Date originalStartTime = trigger.getStartTime(); // save the start time 
Date previousPeriodTime = new Date(originalStartTime.getTime() - interval); 
trigger.setStartTime(previousPeriodTime); 
Date previousFireTime = trigger.getFireTimeAfter(previousPeriodTime); 
trigger.setStartTime(originalStartTime); // reset the start time to be nice 

迭代通过所有的触发器,找到一个是最近过去:

for (String groupName : scheduler.getTriggerGroupNames()) { 
    for (String triggerName : scheduler.getTriggerNames(groupName)) { 
     Trigger trigger = scheduler.getTrigger(triggerName, groupName); 
     // code as detailed above... 
     interval = ... 
     previousFireTime = ... 
    } 
} 

我将它作为练习留给读者将其重构为辅助方法或类。实际上,我使用上述算法在一个子类的委托触发器中,然后我将它放在一个按前面的触发时间排序的集合中。