Состояние гонки Spring Quartz Scheduler

Я подозреваю, что проблема заключается в том, что setOverwriteExistingJobs SchedulerFactoryBean не обеспечивает достаточной защиты.

Один узел будет инициализировать планировщик и решит заменить триггер (точка останова org.quartz.impl.jdbcjobstore.SimpleTriggerPersistenceDelegate#deleteExtendedTriggerProperties )

Сразу после выполнения этого метода триггер больше не будет находиться в базе данных, поэтому, когда другой узел в кластере попытается прочитать его (org.quartz.impl.jdbcjobstore.JobStoreSupport#retrieveTrigger), произойдет сбой с исключением ниже . Из-за этого исключения не запустится все приложение (не только планировщик).

Причина: org.quartz.JobPersistenceException: не удалось получить триггер: не найдена запись для выбора триггера с ключом:

Журналы можно найти по адресу https://github.com/apixandru/case-study/tree/master/spring-boot-quartz/logs (Исключение можно найти на узле Сервер-1 после 4-го рестарта)

Для просмотра всего проекта, демонстрирующего эту проблему, перейдите по адресу https://github.com/apixandru/case-study/tree/master/spring-boot-quartz

Способ, которым мы настраиваем планировщик, здесь

@Bean
JobDetailFactoryBean jobFactoryBean() {
    JobDetailFactoryBean bean = new JobDetailFactoryBean();
    bean.setDurability(true);
    bean.setName("Sampler");
    bean.setJobClass(SampleJob.class);
    return bean;
}

@Bean
SimpleTriggerFactoryBean triggerFactoryBean(JobDetailFactoryBean jobFactoryBean) {
    SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
    bean.setName("Sampler Trigger");
    bean.setRepeatInterval(20_000);
    bean.setJobDetail(jobFactoryBean.getObject());
    return bean;
}

@Bean
SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean triggerFactoryBean, DataSource dataSource, Dependency dependency) {
    Properties props = new Properties();
    props.put("org.quartz.scheduler.instanceId", "AUTO");
    props.put("org.quartz.jobStore.isClustered", "true");

    SchedulerFactoryBean bean = new SchedulerFactoryBean();
    bean.setTriggers(triggerFactoryBean.getObject());
    bean.setSchedulerName("Demo Scheduler");
    bean.setSchedulerContextAsMap(Collections.singletonMap("dependency", dependency));
    bean.setOverwriteExistingJobs(true);
    bean.setDataSource(dataSource);
    bean.setQuartzProperties(props);

    return bean;
}

Это часто происходит на наших рабочих серверах, но локально это намного сложнее (возможно, из-за того, что фактические серверы выделены и имеют гораздо большую мощность, чем моя локальная машина?)

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

Во всяком случае, мне удалось получить эту ошибку локально после примерно 40 повторных развертываний на мой локальный кластерный сервер weblogic.


person Alexandru    schedule 24.09.2016    source источник


Ответы (1)


Проблема в том, что по умолчанию менеджер транзакций не используется, поэтому блокировка не используется.

Чтобы решить эту проблему, необходимо вызвать метод setTransactionManager в schedulerFactoryBean.

person Alexandru    schedule 27.09.2016