Кварц Ява, возобновляющая работу, оправдывает это много раз

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

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

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

scheduler.pauseJob(jobName, jobGroup);

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

scheduler.resumeJob(jobName, jobGroup);

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

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

trigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);

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

4 ответа

Решение

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

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

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

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

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

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

вы можете добавить этот код в org.quartz.impl.jdbcjobstore.JobStoreSupport#resumeTrigger(Connection conn, TriggerKey key)

OperableTrigger trigger = getDelegate().selectTrigger(conn, key);
if (trigger.getNextFireTime().getTime() < System.currentTimeMillis()) {
trigger.setNextFireTime(trigger.getFireTimeAfter(null));
}
JobDetail job = retrieveJob(conn, status.getJobKey());
storeTrigger(conn, trigger, job, true, status.getStatus(), false, false);

Используя этот код, когда приостановленное задание будет возобновлено, оно не будет запущено сразу. С другой стороны, оно будет запущено при следующем времени срабатывания, которое рассчитывается по времени возобновления.

Другие вопросы по тегам