Подтвердить что ты не робот

Quartz Java, возобновляющая работу, многократно ее исключает

Для моего приложения я создаю задания и планирую их с помощью CronTriggers. Каждое задание имеет только один триггер, и оба имени задания и имена триггеров одинаковы. Никакие задания не имеют триггера.

Теперь, когда я создаю cron-триггер, подобный этому "0/1 * * * *?" , который инструктирует задание выполнять каждую секунду, он отлично работает.

Проблема возникает, когда я сначала приостанавливаю работу, вызывая:

scheduler.pauseJob(jobName, jobGroup);

а затем возобновить задание после 50 секунд с:

scheduler.resumeJob(jobName, jobGroup);

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

Я думал, что это связано с установкой по умолчанию для команды пропуска зажигания, но даже после установки инструкций по пропуску запуска триггера после создания:

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);

То же самое происходит. Может кто-нибудь предложить способ исправить это?

4b9b3361

Ответ 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) пользовательский хранилище данных, которое я использую, не поддерживает триггерные подклассы.