6

I want to schedule jobs dynamically based on the schedule configuration provided by the user from the UI. When ever user save the new schedule configuration from the UI then the process has to invoke new job with the new scheduled parameters. There can be n number of configurations as such to execute the same job. Spring supports the implementation of job detail and trigger as following.

Defining jobdetail:

@Bean
public JobDetail jobDetail() {
    return JobBuilder.newJob().ofType(SampleJob.class)
      .storeDurably()
      .withIdentity("Qrtz_Job_Detail")  
      .withDescription("Invoke Sample Job service...")
      .build();
}

Defining trigger:

@Bean
public Trigger trigger(JobDetail job) {
    return TriggerBuilder.newTrigger().forJob(job)
      .withIdentity("Qrtz_Trigger")
      .withDescription("Sample trigger")
      .withSchedule(simpleSchedule().repeatForever().withIntervalInHours(1))
      .build();
}

How can I pass the parameters for job detail and trigger dynamically based on the parameters provided by the user?

1

2 Answers 2

12

The easiest way is to make some configuration by extending SpringBeanJobFactory and @Override createJobInstance method. Then you need to define SchedulerFactoryBean and finally your Scheduler:

@Configuration
public class SchedulerConfiguration {

    public class AutowireCapableBeanJobFactory extends SpringBeanJobFactory {

        private final AutowireCapableBeanFactory beanFactory;

        @Autowired
        public AutowireCapableBeanJobFactory(AutowireCapableBeanFactory beanFactory) {
            Assert.notNull(beanFactory, "Bean factory must not be null");
            this.beanFactory = beanFactory;
        }

        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            Object jobInstance = super.createJobInstance(bundle);
            this.beanFactory.autowireBean(jobInstance);
            this.beanFactory.initializeBean(jobInstance, null);
            return jobInstance;
        }
    }

    @Bean
    public SchedulerFactoryBean schedulerFactory(ApplicationContext applicationContext) {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory(applicationContext.getAutowireCapableBeanFactory()));
        return schedulerFactoryBean;
    }

    @Bean
    public Scheduler scheduler(ApplicationContext applicationContext) throws SchedulerException {
        Scheduler scheduler = schedulerFactory(applicationContext).getScheduler();
        scheduler.start();
        return scheduler;
    }
}

Then anywhere in your application, for example in a RestController you can access the scheduler and schedule a new job:

@RestController
public class ScheduleController {

    @Autowired
    private Scheduler scheduler;

    @GetMapping(value = "/schedule/{detail}/{desc}")
    public String scheduleJob(@PathVariable(value = "detail") String detail, @PathVariable(value = "desc") String desc) throws SchedulerException {
        JobDetail job = newJob(detail, desc);
        return scheduler.scheduleJob(job, trigger(job)).toString();
    }

    private JobDetail newJob(String identity, String description) {
        return JobBuilder.newJob().ofType(SimpleJob.class).storeDurably()
                .withIdentity(JobKey.jobKey(identity))
                .withDescription(description)
                .build();
    }

    private SimpleTrigger trigger(JobDetail jobDetail) {
        return TriggerBuilder.newTrigger().forJob(jobDetail)
                .withIdentity(jobDetail.getKey().getName(), jobDetail.getKey().getGroup())
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1))
                .build();
    }
}

You can control all schedules (pause, stop, restart, delete, etc...) from your Scheduler - look at the documentation

0

This is what JobDataMap parameters are for. You can use these parameters to pass arbitrary parameters to your jobs and triggers. It is generally recommended to use String parameter values to avoid various serialization issues. The JobDataMap API provides auxiliary methods that you can use to convert Strings-valued JobDataMap parameter values to various basic Java objects (Integer, Long, Double, Boolean, etc.).

Please note that JobDataMap parameters specified on the JobDetail level can be overridden on the Trigger level. On the JobDetail level, you typically specify common parameters and/or defaults that should be used for all job executions and you override these defaults and/or add new parameters on the Trigger level.

For details, please refer to Quartz Javadoc:

JobBuilder.html#usingJobData

TriggerBuilder.html#usingJobData

JobDataMap.html

Not the answer you're looking for? Browse other questions tagged or ask your own question.