Кварцевый Java, возобновляющий задание, много раз выполняет его

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

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

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

scheduler.pauseJob(jobName, jobGroup);

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

scheduler.resumeJob(jobName, jobGroup);

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

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

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);

То же самое происходит. Кто-либо может предложить способ зафиксировать это?

22
задан Savvas Dalkitsis 19 December 2009 в 18:02
поделиться

3 ответа

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;
    }
}
30
ответ дан 29 November 2019 в 05:00
поделиться

Если вы приостановите задание, триггер продолжит срабатывать, но выполнение будет стоять в очереди до тех пор, пока задание не будет возобновлено. Это не триггер с пропуском зажигания, поэтому этот параметр не будет иметь никакого эффекта.

Я думаю, что вы хотите программно отключить или удалить триггер cron, а не приостанавливать задание. Если вы захотите возобновить работу, повторно добавьте триггер.

5
ответ дан 29 November 2019 в 05:00
поделиться

По крайней мере, начиная с 1.6.5 (самая ранняя версия кварца у меня под рукой), в планировщике есть метод pauseTrigger, который принимает имя / группу в качестве параметров. Это означает, что вам не обязательно иметь подкласс для каждого типа триггера, который вы используете, и вам не нужно прибегать к забавным трюкам удаления / вставки.

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

1
ответ дан 29 November 2019 в 05:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: