2011-11-23 42 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 = ... 
    } 
} 

我將它作爲練習留給讀者將其重構爲輔助方法或類。實際上,我使用上述算法在一個子類的委託觸發器中,然後我將它放在一個按前面的觸發時間排序的集合中。