3
votes

We are using Spring 4.2.1 and quartz 2.2.1. There are 2 jobs now but we will have more jobs in the future. We want to have ability to turn on/off for each job. There are a couple of approaches for this. One is to create job, jobGroup, trigger and specify the cronExpression in Java code rather than in Spring configuration file. This approach works but it seems to be that it does not sue the Spring Quartz integration and we basically managed the quartz ourselves. Please scroll down after the ScheduledJobUtility class for second approach.

public class ScheduledJobUtility {

    public static Scheduler defineAndScheduleJob(String jobName, String jobGroup, String triggerName, String cronExpression, boolean isJobEnabled,Class clazz) throws SchedulerException {
        Scheduler scheduler = null;
        JobDetail job = newJob(clazz).withIdentity(jobName, jobGroup).build();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerName, jobGroup).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();
        // Schedule the job with the trigger
        scheduler = StdSchedulerFactory.getDefaultScheduler();
        if(!scheduler.isStarted()) {
            scheduler.start();
        }
        if(isJobEnabled) {
            scheduler.scheduleJob(job, trigger);
        }
        return scheduler;
    }
}

The second approach is to find a way to either use the existing method in Spring 4.x "org.springframework.scheduling.quartz" package. I have been trying to add my own logic in the afterPropertiesSet() method

private boolean enableJob1 = true;

private boolean enableJob2 = false;

// @Override
public void afterPropertiesSet() throws Exception {
    super.afterPropertiesSet();
    Scheduler scheduler = super.getScheduler();
    if (enableJob1) {    
       JobDetail jobDetail1 = scheduler.getJobDetail(JobKey.jobKey("Job1",                "JobGroup1");
       Trigger trigger1 = scheduler.getTrigger(TriggerKey.triggerKey("myTrigger1","jobGroup1"));
       super.getScheduler().scheduleJob(jobDetail1, trigger1);                
}


if (enableRetryRenditions) {
    if (enableJob2) {    
       JobDetail jobDetail2 = scheduler.getJobDetail(JobKey.jobKey("Job2",                "JobGroup2");
       Trigger trigger2 = scheduler.getTrigger(TriggerKey.triggerKey("myTrigger2","jobGroup2"));
       super.getScheduler().scheduleJob(jobDetail2, trigger2);                
}
}
}

I found this, http://quartz-scheduler.org/documentation/quartz-2.1.x/cookbook/UnscheduleJob

// Unschedule a particular trigger from the job (a job may have more than one trigger)
scheduler.unscheduleJob(triggerKey("trigger1", "group1"));

MySchedulerFactoryBean extends SchedulerFactoryBean"org.springframework.scheduling.quartz.SchedulerFactoryBean and is used in the configuration file

   <bean class="com.spring.utility.MySchedulerFactoryBean">
        <property name="jobDetails">
            <list>
                <ref bean="jobDetail1"/>
                <ref bean="jobDetail2"/>
            </list>
        </property>

        <property name="triggers">
            <list>
                <ref bean="cronTrigger1"/>
                <ref bean="cronTrigger2"/>
            </list>`enter code here`
        </property>

        <property name="autoStartup" value="true" />
    </bean>

I did quite a bit search but could not find too much discussions on turn on/off each job. I have been looking into the "org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" and "org.springframework.scheduling.quartz.CronTriggerFactoryBean" to see if I can extend that class and add my own logic to turn on and off individual job. There is a property ""autoStartup" for "org.springframework.scheduling.quartz.SchedulerFactoryBean" but I do not want to create instance of SchedulerFactoryBean for each job. That would be messy for 50 jobs.

1
The spring integration with quartz is quite primitive in the are of job management... meaning that the configuration is very static. If you want to be able to manage the jobs, my suggestion is to write some code that deals with this, rather than using spring. This becomes even worse if you're using quartz in clustered mode, as Spring won't update jobs when they are changed in the configuration file. - Augusto
Tried this way to turn off the job: public class CronTriggerFactoryBeanExtension extends CronTriggerFactoryBean { private boolean enable; public boolean isEnable() { return enable; } public void setEnable(boolean enable) { this.enable = enable; } @Override public void afterPropertiesSet() throws ParseException { if(enable) { super.afterPropertiesSet(); } } } <bean id="cronTrigger1" class="com.spring.service.CronTriggerFactoryBeanExtension"> ..... <property name="enable" value="false"/> </bean> - Oliver Li
Sorry, comment has to be short. I got nullpointerException when I set the enable = false Caused by: org.quartz.SchedulerException: Registration of jobs and triggers failed: null [See nested exception: java.lang.NullPointerException] at org.springframework.scheduling.quartz.SchedulerAccessor.registerJobsAndTriggers(SchedulerAccessor.java:254) java.lang.NullPointerException at org.springframework.scheduling.quartz.SchedulerAccessor.addTriggerToScheduler(SchedulerAccessor.java:291) at org.springframework.scheduling.quartz.SchedulerAccessor.registerJobsAndTriggers(SchedulerAccessor.java:235) - Oliver Li

1 Answers

1
votes

To "turn off" your jobs, you can simply pause these jobs by invoking the pauseJob method. This call pauses all triggers associated with a particular job. To resume the job (actually its triggers), you simply call the resumeJob method.

There are even methods available to pause/resume job and trigger groups.

So there is no need to register/unregister jobs using the schedulerJob and unscheduleJobs method. This way, you job and trigger list will stay intact.

Since Quartz and Spring APIs do not allow you to set the "paused" flag when you create the trigger, you will have to use a scheduler with autoStartup=false and then in some listener, before you call scheduler.start(), you will have to iterate through the list of your jobs and invoke one of pauseJob/resumeJob methods on them.

I do not know your exact use-case and if you only need to pause/resume your jobs programatically, but if you prefer doing this from a GUI, then I recommend that your check QuartzDesk (our product). Even the free (Lite) edition allows you to perform these two basic operations on jobs, triggers, job group and trigger groups.