我怀疑问题是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服务器之后,我设法在本地获得了这个错误。
答案 0 :(得分:2)
问题在于,默认情况下不使用任何事务管理器,因此不使用锁定。
要解决此问题,需要调用schedulerFactoryBean的setTransactionManager方法。