| 26 April 2007 |
Just a small post about something I noticed in Quartz. I wanted to offer the user a screen with functionality so they could (re)schedule a batch job which then would do all kinds of batch stuf. To schedule the job in my application I used the following Java code:
-
public void resetScheduleJob() throws CustomSystemException {
-
-
StdScheduler scheduler = (StdScheduler)MyQueueContext.getContext().getBean("scheduler");
-
-
CronTriggerBean trigger = (CronTriggerBean)MyQueueContext.getContext().getBean("batchProducerTrigger");
-
-
try {
-
trigger.setCronExpression(getCronExpression());
-
-
scheduler.scheduleJob(trigger.getJobDetail(), trigger);
-
-
throw new CustomSystemException (pe);
-
} catch (SchedulerException se) {
-
throw new CustomSystemException (se);
-
}
-
LOG.info("Next run will be at: " + trigger.getNextFireTime());
-
}
-
}
-
-
// Small trick to get the hours of the day correct.
-
String hours = null;
-
if (startTime> endTime) {
-
hours = endTime + "-23,0-" + startTime;
-
} else if (startTime <endTime) {
-
hours = startTime + "-" + endTime;
-
} else {
-
hours = "0";
-
}
-
return "0 0/" + interval + " " + hours + " ? * " + days;
-
}
So this code runs fine the first time when it is called. But when you call it the second time (after the job exists) you will get:
org.quartz.ObjectAlreadyExistsException: Unable to store Job with name: 'batchProducerJob' and group: 'DEFAULT', because one already exists with this identification.
So I rewrote my code to:
-
public void resetScheduleJob() throws CustomSystemException {
-
StdScheduler scheduler = (StdScheduler)MyQueueContext.getContext().getBean("scheduler");
-
-
CronTriggerBean trigger = (CronTriggerBean)MyQueueContext.getContext().getBean("batchProducerTrigger");
-
-
try {
-
trigger.setCronExpression(getCronExpression());
-
-
scheduler.rescheduleJob(job.getName(), job.getGroup(), trigger);
-
-
scheduler.start();
-
-
throw new CustomSystemException (pe);
-
} catch (SchedulerException se) {
-
throw new CustomSystemException (se);
-
}
-
LOG.info("Next run will be at: " + trigger.getNextFireTime());
-
}
Now this code won't fail if you call it several times..... Actually, it doesn't do anything! I would expect an exception if the scheduler must have an existing job before it can reschedule one. But nothing there, I only found out that my job wasn't started at all. So the trick is to check if there is a job with the same name, and if one is found, do the reschedule, otherwise the 'normal' schedule. Since I wasn't expecting this behaviour I thought may be there are more persons running into this so here is the solution:
-
public void resetScheduleJob() throws CustomSystemException {
-
StdScheduler scheduler = (StdScheduler)MyQueueContext.getContext().getBean("scheduler");
-
-
CronTriggerBean trigger = (CronTriggerBean)MyQueueContext.getContext().getBean("batchProducerTrigger");
-
-
try {
-
trigger.setCronExpression(getCronExpression());
-
-
JobDetail job = scheduler.getJobDetail(trigger.getJobDetail().getName(), trigger.getJobDetail().getGroup());
-
LOG.debug("Job found = " + job);
-
-
if (job == null) {
-
scheduler.scheduleJob(trigger.getJobDetail(), trigger);
-
} else {
-
scheduler.rescheduleJob(job.getName(), job.getGroup(), trigger);
-
}
-
-
scheduler.start();
-
-
throw new CustomSystemException (pe);
-
} catch (SchedulerException se) {
-
throw new CustomSystemException (se);
-
}
-
LOG.info("Next run will be at: " + trigger.getNextFireTime());
-
}
And to make this example complete here is my Spring configuration:
-
<?xml version="1.0" encoding="UTF-8"?>
-
<!DOCTYPE beans SYSTEM "../dtd/spring-beans.dtd">
-
<beans>
-
<bean id="batchProducerJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
-
<property name="targetObject" ref="batchProducer" />
-
<property name="targetMethod" value="start" />
-
</bean>
-
<bean id="batchProducerTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
-
<property name="jobDetail" ref="batchProducerJob" />
-
</bean>
-
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
-
<!-- intentionally left empty -->
-
</bean>
-
<bean id="batchProducerScheduler" class="net.pascalalma.batch.schedulers.BatchProducerScheduler">
-
<property name="startTime" value="${batch.produce.starthour}" />
-
<property name="endTime" value="${batch.produce.endhour}" />
-
<property name="interval" value="${batch.produce.interval}" />
-
<property name="days" value="${batch.produce.days}" />
-
</bean>
-
</beans>


8 comments to 'Scheduling with Spring and Quartz'
25 July 2007
[...] I posted before here I am using Quartz scheduler to schedule some batch jobs. It seemed to work fine but now while we [...]
14 November 2007
post the whole code!
11 August 2008
Hi there,
I'm a newbie in quartz and I was confused much about why it wouldn't update either the job detail nor the trigger on db. I found your blog, and it seems that we have to reschedule it.
Thanks a lot! :)
11 August 2008
Correction: I found your blog, and now I know that we have to reschedule it.
:D
Thx againn
18 August 2008
HI there,
this is a great post, but i have a problem, I need to reschedule an already initiated job.
in the spring config example above, the scheduler is empty, so no triggers are initiated when the application is deployed, and the rescheduling code works like a charm.
But when i fill the scheduler bean with two or more triggers, like this:
applicationContext
and try to reschedule them, the code doesnt work, and i get no errors in the console.
I hope theres a solution for this thing and somebody can help me
thx anyway
18 August 2008
oops, i dont know why the code y wanted to upload didnt, so the thing is, that inside the scheduler bean, i added a property tag with the list of 4 triggers on it.
thanks
20 August 2008
Hi Edu,
Posting HTML in the comments can be a possible security risk, unfortunately, I found out in the past.
If you still want me to look at it you can send the piece of code to blog@pascalalma.net and I will have a look, but I can't promise anything ;-)
12 November 2008
I think scheduler.rescheduleJob args are trigger name ,trigger group and new trigger object.