Quartz Java, возобновляющая работу, многократно ее исключает
Для моего приложения я создаю задания и планирую их с помощью CronTriggers. Каждое задание имеет только один триггер, и оба имени задания и имена триггеров одинаковы. Никакие задания не имеют триггера.
Теперь, когда я создаю cron-триггер, подобный этому "0/1 * * * *?" , который инструктирует задание выполнять каждую секунду, он отлично работает.
Проблема возникает, когда я сначала приостанавливаю работу, вызывая:
scheduler.pauseJob(jobName, jobGroup);
а затем возобновить задание после 50 секунд с:
scheduler.resumeJob(jobName, jobGroup);
Я вижу, что за эти 50 секунд задание не выполнялось по запросу. Но в тот момент, когда я возобновляю работу, я вижу 50 исполнений задания в то же время!!!
Я думал, что это связано с установкой по умолчанию для команды пропуска зажигания, но даже после установки инструкций по пропуску запуска триггера после создания:
trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
То же самое происходит. Может кто-нибудь предложить способ исправить это?
Ответы
Ответ 1
CronTrigger
работает, запоминая nextFireTime
. После создания триггера инициализируется nextFireTime
. Каждый раз, когда запускается задание, nextFireTime
обновляется. Поскольку задание не запускается, когда приостановлено nextFireTime
остается "старым". Поэтому после возобновления работы триггер вернет каждое старое время запуска.
Проблема заключается в том, что триггер не знает, что он приостановлен. Чтобы преодолеть это, это обработка пропуска зажигания. После возобновления заданий будет вызываться триггерный метод updateAfterMisfire()
, который исправляет nextFireTime
. Но нет, если разница между nextFireTime
и теперь меньше misfireThreshold. Тогда метод никогда не вызывается. Это пороговое значение по умолчанию - 60 000. Таким образом, если ваш период паузы будет длиннее 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;
}
}
Ответ 2
Если вы приостанавливаете задание, триггер будет продолжать работать, но выполнение будет стоять в очереди до тех пор, пока работа не будет возобновлена. Это не срабатывание триггера пропускания, поэтому настройка не будет иметь эффекта.
Что вы хотите сделать, я думаю, программно отключить или удалить триггер cron, а не приостанавливать работу. Когда вы хотите возобновить, повторите добавление триггера.
Ответ 3
Так как 1.6.5 по крайней мере (самая ранняя версия кварца у меня под рукой), планировщик имеет метод pauseTrigger, который принимает имя/группу в качестве параметров. Это означает, что вам не нужно иметь подкласс для каждого типа триггера, который вы используете, и вам не нужно делать фанки для удаления/вставки.
Оба они важны для меня, потому что 1) наша база данных имеет строгую политику без удаления и 2) пользовательский хранилище данных, которое я использую, не поддерживает триггерные подклассы.