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