Кварц Java, возобновляющий работу, оправдывает это много раз - PullRequest
21 голосов
/ 19 декабря 2009

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

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

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

scheduler.pauseJob(jobName, jobGroup);

, а затем возобновить работу, скажем, через 50 секунд:

scheduler.resumeJob(jobName, jobGroup);

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

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

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);

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

Ответы [ 3 ]

28 голосов
/ 27 декабря 2009

CronTrigger работает, помня nextFireTime. После создания триггера инициализируется nextFireTime. Каждый раз при запуске задания nextFireTime обновляется. Поскольку задание не запускается при паузе nextFireTime остается «старым». Поэтому после возобновления работы триггер будет возвращаться при каждом старом времени запуска.

Проблема в том, что триггер не знает, что он приостановлен. Для преодоления этого есть эта обработка осечки. После возобновления работ будет вызван триггерный метод updateAfterMisfire(), который исправляет nextFireTime. Но нет, если разница между nextFireTime и сейчас меньше, чем misfireThreshold . Тогда метод никогда не вызывается. Значение этого порога по умолчанию составляет 60000. Таким образом, если ваш период паузы будет дольше 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;
    }
}
5 голосов
/ 19 декабря 2009

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

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

1 голос
/ 14 февраля 2010

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

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

...