Correct way to persist Quartz triggers in database

前端 未结 2 945
温柔的废话
温柔的废话 2020-12-29 14:57

I\'m quite new to Quartz and now I need to schedule some jobs in Spring web application.

I know about Spring + Quartz integration (I\'m using Spring v 3.1.1) but I\'

相关标签:
2条回答
  • 2020-12-29 15:39

    I suppose there are quite some documentation available for Spring and Quartz JDBC job store integration; for instance:

    • If you're using annotation configuration: http://java.dzone.com/articles/configuring-quartz
    • If you're using XML configuration: http://arkuarku.wordpress.com/2011/01/06/spring-quartz-using-jdbcjobstore-simple/
    • Quartz Job Stores: http://quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-09
    • Spring 3.x SchedulerFactoryBean for Quartz
    0 讨论(0)
  • 2020-12-29 15:51

    Here is one way I 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 a job in my application I store the details of the job in the database. This service is called by one of my controllers and it schedules the job:

    @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 I build contains detail about the job and is eventually passed to a utility for scheduling jobs. Here is that code for the utility method that actually schedules the job. Notice that in my service I autowire the JobScheduler and pass it to the JobContext. Also notice that I store the job in the database using my repository.

    /**
     * Schedules a DATA_MINING_JOB for the client. The job will attempt to enter
     * followers of the target into the database.
     */
    @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 all of this code executes I two things have happened, my job is store in the database and its been scheduled using the quartz scheduler. Now if the application restarts I want to reschedule my jobs with the scheduler. To do this I register a bean that implements ApplicationListener<ContextRefreshedEvent> which is called by Spring each time the container restarts or is started.

    <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.");
    
            //TODO: Modify this call to only pull completed & enabled jobs
            for (ApplicationJob applicationJob : jobRepository.findAll()) {
                if (applicationJob.getIsEnabled() && (applicationJob.getIsCompleted() == null || !applicationJob.getIsCompleted())) {
                    JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, applicationJob));
                }
            }       
        }
    
    }
    

    This class autowires the scheduler and a repository that grabs instances of each of my jobs that implement the ApplicationJob interface. Using the information from these database records I can use my scheduler utility to reconstruct my jobs.

    So basically I manually store the jobs in my database and manually schedule them by injecting a instance of the Scheduler in appropriate beans. To rescheduled them, I query my database and then schedule them using the ApplicationListener to account for restarts and starts of the container.

    0 讨论(0)
提交回复
热议问题