Here is one way to handle this scenario.
First, in my Spring configuration, I specify a SchedulerFactoryBean from which I can inject the Scheduler into other beans.
<bean name="SchedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="applicationContextSchedulerContextKey"> <value>applicationContext</value> </property> </bean>
Then, when I create the task in my application, I save the details of the task in the database. This service is called by one of my controllers, and it assigns a task:
@Component public class FollowJobService { @Autowired private FollowJobRepository followJobRepository; @Autowired Scheduler scheduler; @Autowired ListableBeanFactory beanFactory; @Autowired JobSchedulerLocator locator; public FollowJob findByClient(Client client){ return followJobRepository.findByClient(client); } public void saveAndSchedule(FollowJob job) { job.setJobType(JobType.FOLLOW_JOB); job.setCreatedDt(new Date()); job.setIsEnabled(true); job.setIsCompleted(false); JobContext context = new JobContext(beanFactory, scheduler, locator, job); job.setQuartzGroup(context.getQuartzGroup()); job.setQuartzName(context.getQuartzName()); followJobRepository.save(job); JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, job)); } }
The JobContext line I contains detailed information about the job and is ultimately passed to the task scheduling utility. Here is the code for a utility method that actually plans to work. Please note that in my service I scroll through the JobScheduler and pass it to the JobContext . Also note that I am storing the job in the database using my repository.
@Override public void schedule(JobContext context) { Client client = context.getNetworkSociallyJob().getClient(); this.logScheduleAttempt(context, client); JobDetail jobDetails = JobBuilder.newJob(this.getJobClass()).withIdentity(context.getQuartzName(), context.getQuartzGroup()).build(); jobDetails.getJobDataMap().put("job", context.getNetworkSociallyJob()); jobDetails.getJobDataMap().put("repositories", context.getRepositories()); Trigger trigger = TriggerBuilder.newTrigger().withIdentity(context.getQuartzName() + "-trigger", context.getQuartzGroup()) .withSchedule(cronSchedule(this.getSchedule())).build(); try { context.getScheduler().scheduleJob(jobDetails, trigger); this.logSuccess(context, client); } catch (SchedulerException e) { this.logFailure(context, client); e.printStackTrace(); } }
So, after doing all this code, I did two things: my work is stored in a database and scheduled using a quartz scheduler. Now, if the application restarts, I want to reschedule my tasks using the scheduler. To do this, I will register a bean that implements the ApplicationListener<ContextRefreshedEvent> , which is called by Spring each time the container is restarted or launched.
<bean id="jobInitializer" class="com.network.socially.web.jobs.JobInitializer"/>
JobInitializer.class
public class JobInitializer implements ApplicationListener<ContextRefreshedEvent> { Logger logger = LoggerFactory.getLogger(JobInitializer.class); @Autowired DataMiningJobRepository repository; @Autowired ApplicationJobRepository jobRepository; @Autowired Scheduler scheduler; @Autowired JobSchedulerLocator locator; @Autowired ListableBeanFactory beanFactory; @Override public void onApplicationEvent(ContextRefreshedEvent event) { logger.info("Job Initilizer started.");
This class auto-installs the scheduler and repository, which grabs instances of each of my jobs implementing the ApplicationJob interface. Using the information from these database entries, I can use my scheduler utility to restore my jobs.
So, basically I manually store tasks in my database and manually schedule them by inserting an instance of Scheduler into the appropriate beans. To migrate them, I query my database and then plan them using ApplicationListener to account for the restart and launch of the container.