简体   繁体   English

运行错过的Quartz作业

[英]Running A Missed Quartz Job

I'm using Quartz with Spring to run a specific task at midnight on the first day of the month. 我正在使用Quartz with Spring在每个月的第一天午夜运行特定任务。 I have tested the job by setting my server date & time to be 11:59 on the last day of the month, starting the server and observing the task run when it turns to 12:00, but I'm concerned about cases where the server (for whatever reason) may not be running at midnight on the first of the month. 我已经通过将我的服务器日期和时间设置为当月最后一天的11:59来测试该作业,启动服务器并在转到12:00时观察任务运行,但我担心的情况是服务器(无论出于何种原因)可能不会在本月的第一天午夜运行。

I'd assumed that misfire handling in Quartz would care for this, but maybe I'm mistaken on that? 我认为Quartz中的失火处理会关心这一点,但也许我错了吗?

Can anyone advise me on how I might be able to handle this? 任何人都可以告诉我如何处理这个问题? I'd really prefer not to create a job that runs every 'x' seconds/minutes/hours and check to see if I need to run the job if I can avoid it. 我真的不想创建一个每隔'x'秒/分钟/小时运行的作业,并检查是否需要运行该作业,如果我可以避免它。

I'm also curious as to why I'm not seeing any Quartz related logging info, but that's a secondary issue. 我也很好奇为什么我没有看到任何与Quartz相关的日志信息,但这是次要问题。

Here is my spring configuration for the task: 这是我的任务弹簧配置:

<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>

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW is for the purpose you mentioned and if you suspect a shutdown of the server(s) you should definitely persist your jobs out of the JVM memory (ex: by using a JDBCJobStore instead of a RAMJobStore). MISFIRE_INSTRUCTION_FIRE_ONCE_NOW就是您提到的目的,如果您怀疑服务器已关闭,您肯定应该将作业保留在JVM内存之外(例如:使用JDBCJobStore而不是RAMJobStore)。

RAMJobStore is fast and lightweight, but all scheduling information is lost when the process terminates. RAMJobStore快速而轻量级,但是当进程终止时,所有调度信息都会丢失。

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

JDBCJobStore is used to store scheduling information (job, triggers and calendars) within a relational database. JDBCJobStore用于在关系数据库中存储调度信息(作业,触发器和日历)。

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

Hope it help. 希望它有所帮助。

I too have faced the problem of wanting to run the last scheuled job on a server restart. 我也遇到过想要在服务器重启时运行最后一个计划作业的问题。

This is the solution I have found is to go back one time interval for the trigger and calculate what would have been the next firing time. 这是我发现的解决方案是返回触发器的一个时间间隔并计算下一个触发时间。 By iterating through all the triggers the most recent time that a trigger should have fired in the past can be determined. 通过迭代所有触发器,可以确定触发器应该在过去触发的最近时间。


Calculate the interval between each firing: 计算每次射击之间的间隔:

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

Find the next firing time for one time until interval in the past: 找到下一次射击时间,直到过去的间隔:

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

I have found that if you are using a CronTrigger this prevents you asking for a fire time in the past. 我发现如果你使用的是CronTrigger这可以防止你在过去要求火时间。 To work around this I modify the start time, so the above snippet becomes: 要解决此问题,我修改了开始时间,因此上面的代码片段变为:

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

Iterate through all of the triggers and find the one that is most recently in the past: 迭代所有触发器并找到过去最近的触发器:

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

I'll leave it as an exercise to the reader to refactor this into helper methods or classes. 我将把它作为练习留给读者将其重构为辅助方法或类。 I actually use the above algorithm in a subclassed delegating trigger that I then place in a set sorted by previous firing times. 我实际上在子类委托触发器中使用上述算法,然后将其放置在按先前触发时间排序的集合中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM