Выполнение пропущенной кварцевой работы - PullRequest
5 голосов
/ 23 ноября 2011

Я использую Quartz with Spring для запуска определенной задачи в полночь первого дня месяца. Я проверил задание, установив дату и время моего сервера равными 11:59 в последний день месяца, запустив сервер и наблюдая за выполнением задания, когда оно переходит в 12:00, но меня беспокоят случаи, когда Сервер (по какой-либо причине) может не работать в полночь первого числа месяца.

Я предполагал, что обработка осечки в Кварце будет заботиться об этом, но, может быть, я ошибаюсь в этом?

Может кто-нибудь посоветовать мне, как я могу справиться с этим? Я действительно предпочел бы не создавать задание, которое запускается каждые «х» секунд / минут / часов, и проверить, нужно ли мне запускать задание, если смогу его избежать.

Мне также любопытно, почему я не вижу никакой информации о журнале, связанной с Quartz, но это вторичная проблема.

Вот моя весенняя конфигурация для задачи:

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

2 голосов
/ 01 января 2012

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW предназначен для упомянутой вами цели, и если вы подозреваете отключение сервера (-ов), вам определенно следует сохранять свои задания вне памяти 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 голосов
/ 30 января 2012

Я тоже столкнулся с проблемой желания запустить последнее запланированное задание при перезапуске сервера.

Это решение, которое я нашел, состоит в том, чтобы вернуться назад на один временной интервал для триггера и вычислить, что было бы следующим временем срабатывания. Итерируя по всем триггерам, можно определить самое последнее время, когда триггер должен был срабатывать в прошлом.


Рассчитайте интервал между каждой стрельбой:

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

Я обнаружил, что если вы используете CronTrigger, это не позволяет вам задавать вопрос о времени пожара в прошлом. Чтобы обойти это, я изменяю время запуска, поэтому приведенный выше фрагмент кода становится следующим:

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 = ...
    }
}

Я оставлю читателю в качестве упражнения рефакторинг этого в вспомогательные методы или классы. Я фактически использую вышеупомянутый алгоритм в триггере делегирования подкласса, который затем помещаю в набор, отсортированный по предыдущему времени срабатывания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...