Reputation: 539
I am working with a scenario where we have one database with multiple schemas, one schema for each customer. This allows each customer to set different schedules for their jobs. All schemas have the same set of jobs, only the schedules differ.
I need to write one Spring-Boot app to run all jobs from all schemas.
It seems like this would be done by defining different quartz.properties for each schema, and then configuring a different Scheduler for each one, like this:
@SpringBootApplication
@Configuration
public class MyApplication{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Bean
public Scheduler schedulerA(Trigger trigger, JobDetail job) {
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(new ClassPathResource("quartzA.properties").getInputStream());
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(springBeanJobFactory());
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}
@Bean
public Scheduler schedulerB(Trigger trigger, JobDetail job) {
StdSchedulerFactory factory = new StdSchedulerFactory();
factory.initialize(new ClassPathResource("quartzB.properties").getInputStream());
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(springBeanJobFactory());
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}
}
My question is, is this correct? Can I just define these schedulers in my SpringBootApplication class annotated with @Configuration, and expect it to work (assuming the properties are correct)? Am I missing anything?
Upvotes: 4
Views: 7017
Reputation: 558
Inspired by the above example I found a way to use configurations managed in application properties which seems to be easier and more consistent with the rest of the Spring-Boot app. It is particularly useful to reuse the data source configuration. Any number of beans of the second kind is possible.
@Configuration
class MainQuartzConfiguration {
/**
* Main scheduler bean where all jobDetails, calendars and trigger beans are attached.
*
*/
@Primary @Bean
public SchedulerFactoryBean mainScheduler(QuartzProperties properties,
ObjectProvider<SchedulerFactoryBeanCustomizer> customizers,
ObjectProvider<JobDetail[]> jobDetails, Map<String, Calendar> calendars,
ObjectProvider<Trigger[]> triggers, ApplicationContext applicationContext) {
SchedulerFactoryBean factory = new QuartzAutoConfiguration(properties, customizers, jobDetails, calendars, triggers, applicationContext)
.quartzScheduler();
factory.setSchedulerName("mainScheduler");
return factory;
}
}
@Configuration
class AnotherConfiguration {
/**
* Second scheduler bean which has the same configuration but different thread count and thread priority.
*/
@Bean
SchedulerFactoryBean secondScheduler(
QuartzProperties properties,
ObjectProvider<SchedulerFactoryBeanCustomizer> customizers,
@Value("${spring.quartz.properties.secondScheduler.org.quartz.threadPool.threadPriority:7}") int threadPriority,
@Value("${spring.quartz.properties.secondScheduler.org.quartz.threadPool.threadCount:1}") int threadCount,
ApplicationContext applicationContext)
{
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
schedulerFactoryBean.setJobFactory(jobFactory);
schedulerFactoryBean.setSchedulerName("secondScheduler");
schedulerFactoryBean.setAutoStartup(properties.isAutoStartup());
schedulerFactoryBean
.setStartupDelay((int) properties.getStartupDelay().getSeconds());
schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(
properties.isWaitForJobsToCompleteOnShutdown());
Properties propertiesVariant = new Properties();
propertiesVariant.putAll(properties.getProperties());
propertiesVariant.setProperty("org.quartz.threadPool.threadPriority", Integer.toString(threadPriority));
propertiesVariant.setProperty("org.quartz.threadPool.threadCount", Integer.toString(threadCount));
schedulerFactoryBean.setQuartzProperties(propertiesVariant);
schedulerFactoryBean.setJobDetails(CatalogBenchmarkJob.createJob());
customizers.orderedStream().forEach(
(customizer) -> customizer.customize(schedulerFactoryBean));
return schedulerFactoryBean;
}
}
Upvotes: 1
Reputation: 3424
My question is, is this correct? Can I just define these schedulers in my SpringBootApplication class annotated with @Configuration
This is correct. Alternatively you can use Spring @Schelduled annotation with a Cron defined in properties files.
@Scheduled(cron = "0 15 10 15 * ?")
public void scheduleTaskUsingCronExpression() {
.
.
.
But, if you want more control over the jobs like failover, retry policy or track and run/rerun jobs from a dashboard. Think of spring-batch
Upvotes: 2