Spring Quartz Scheduler竞争条件

时间:2016-09-24 07:05:53

标签: java spring spring-boot scheduled-tasks quartz-scheduler

我怀疑问题是SchedulerFactoryBean的setOverwriteExistingJobs没有提供足够的保护。

一个节点将初始化调度程序,它将决定替换触发器(断点org.quartz.impl.jdbcjobstore.SimpleTriggerPersistenceDelegate #leleExtendedTriggerProperties)

在执行此方法之后,触发器将不再在数据库中,因此当集群中的另一个节点尝试读取它时(org.quartz.impl.jdbcjobstore.JobStoreSupport#retrieveTrigger)它将失败以下例外。由于此异常,整个应用程序将无法启动(而不仅仅是调度程序)。

  

引起:org.quartz.JobPersistenceException:无法检索   触发:未找到选择带键的触发器的记录:

可以在https://github.com/apixandru/case-study/tree/master/spring-boot-quartz/logs找到日志 (可在第4次重启后在Server-1节点上找到例外)

对于演示此问题的整个项目,请转到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上放置一个断点,然后在执行之后启动第二个服务器,您将获得此异常

无论如何,在我重新部署到本地集群weblogic服务器之后,我设法在本地获得了这个错误。

1 个答案:

答案 0 :(得分:2)

问题在于,默认情况下不使用任何事务管理器,因此不使用锁定。

要解决此问题,需要调用schedulerFactoryBean的setTransactionManager方法。