Correct way to persist Quartz triggers in database

百般思念 提交于 2019-11-29 03:54:00

问题


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'm wondering if this is the right way to follow.

In particular I need to persist my scheduled tasks in a DB so I can re-initialize them when application is restarted.

Are there some utilities provided by Spring scheduling wrapper to do this? Can you suggest me some "well known" approach to follow?


回答1:


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.




回答2:


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


来源:https://stackoverflow.com/questions/17402112/correct-way-to-persist-quartz-triggers-in-database

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!