Schedulers play a key role of running batch processes in software applications. As a matter of fact Java language supports several key frameworks that assist software developers in dynamic job scheduling. Fulcrum Scheduler, Oddjob Scheduler, JDRing, Quartz Scheduler and J2EE Scheduler are some of the popular job schedulers. Out of all these, Quartz Scheduler is the most widely used job scheduler, as it offers impressive features including dynamic job scheduling and it is comparatively easier to use than other job schedulers.
Quartz is an advanced and powerful dynamic job scheduling framework (open source). It allows software developers to schedule jobs at a desired time. Furthermore, it provides provisions to edit, pause/resume and delete the scheduled job. Utilizing Quartz, software developers can create simple as well as complex schedules to execute thousands of jobs.
In this blog post, we will learn ‘How to schedule a job dynamically using the Quartz Scheduler’. Subsequently, we will also figure out the process to edit, pause/resume and delete scheduled jobs. We have considered a use case, which helps readers easily understand the process of scheduling jobs using Quartz Scheduler. As a software developer, if you are required to schedule jobs on daily, weekly, monthly or yearly basis, it is possible to execute the same using Quartz scheduler.
Job Schedule Frequencies
Below are some of the job schedule frequencies that can be setup using Quartz Scheduler:
- Daily
- Weekly
- Monthly
- Yearly
Job Schedule Recurrence Options
Quartz Scheduler further allows software developers to define the end recurrence options. Below are the three end recurrence options available in Quartz:
- Never End
- End After <No. of Occurrences>
- End By <Particular Date>
Solution Approach
In order to create the above job schedule frequencies with the mentioned end recurrence, software developers have to create a user interface using jQuery’s recurrenceinput.js library, Google’s RFC RRULE jar and Quartz Job Scheduler API. The recurrenceinput.js library captures the user selection in the form of RRULE syntax. The recurring schedule is captured as mentioned below:
RRULE:FREQ=WEEKLY;BYDAY=MO,WE;COUNT=4
Using Google’s RFC RRULE API, developers can parse the recurrent rule(rrule) and subsequently, by making use of custom logic convert it to Quartz’s CRON expression. Below is a step-by-step guide that would help developers achieve the above mentioned activity:
Step 1- How to Configure Quartz Scheduler?
The below code helps developers to configure the Quartz Scheduler:
[java]
<bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
<property name="configLocation" value="classpath:quartz.properties" />
<property name="overwriteExistingJobs" value="true" />
</bean>
[/java]
applicationContextSchedulerContextKey – This property is used to pass a message to the Quartz Scheduler i.e. how and where to find Spring’s applicationContext. Furthermore, while executing a job, the Quartz Scheduler can access Spring beans using scheduler context. Here’s the code:
[java]
ApplicationContext appContext= jobExecutionContext.get(“applicationContextSchedulerContextKey”)
[/java]
quartz.properties – This function is used to define all Quartz Scheduler properties; here are few examples of these properties (jobStore, datasource, threadPool, plugin, etc.).
Step 2 – How to Implement a Quartz Scheduler Job?
In order to implement a Quartz Scheduler Job, developers should make use of the Job class to implement the execute(JobExecutionContext) method of the Quartz Job interface. The Job class throws JobExecutionException, if an error occurs during job execution, JobExecutionContext should be populated with all the required information to run the job, while adding/editing a job. Below is the sample job code, which would help us understanding the concept better:
[java]
Public class MyJob implements Job{
@Override
public void execute(final JobExecutionContext context)throws JobExecutionException {
JobDetail jobDetail = context.getJobDetail();
Long reportIdToRun =jobDetail.getKey();
// do the actual job logic here. May be running a report, sending an
// email, purging file system directory, etc.
}
}
[/java]
Step 3 – How to Add a New Job to Quartz Scheduler?
To add a new job to the Quartz Job Scheduler for dynamic job scheduling, developers have to make use of JobDetail and Trigger components. The JobDetail interface is created using a unique key and a Job class, whereas the Trigger component is created using a unique trigger key. Lastly, schedules are created using TriggerBuilder with start and end dates. Here’s a sample job code that helps us gain a better understanding on the process of adding a new job schedule:
[java]
scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = reportIdToRun; //
JobDetail jobDetail= newJob(MyJob.class).withIdentity(jobKey).build();
Trigger trigger= newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(cronExpression)).startAt(startDate).endAt(endDate).build()
scheduler.scheduleJob(jobDetail, trigger);
[/java]
We have learnt the process of adding a job to Quartz Scheduler in three simple steps. Now, let’s figure out the process of editing, pausing, and deleting existing jobs in Quartz Scheduler.
How to Edit an Existing Job?
In order to edit/update an existing job in Quartz Scheduler developers need to:
- Update the job details
- Update the trigger details
Here’s the code, which would allow developers to complete this activity:
[java]
scheduler.addJob(updatedJobDetail, true, true); // 2nd parameter true means updating the existing job with the updated one.
scheduler.rescheduleJob(oldTriggerKey, newTrigger);
[/java]
How to Pause/Resume an Existing Job?
In order to Pause/Resume an existing job in Quartz Scheduler, developers can use the below code:
[java]
scheduler.pauseJob(jobKey);
scheduler.resumeJob(jobKey); // the job will be resumed based on the quartz misfire instructions.
[/java]
How to Delete an Existing Job?
Deleting an existing job in Quartz Scheduler is a fairly easy task. Below is the code that would allow developers to delete an existing job:
- Unschedule the job
- Delete the job
[java]
scheduler.unscheduleJob(jobKey);
scheduler.deleteJob(jobKey);
[/java]
Technology Stack
To demonstrate the functioning of Quartz Scheduler, we have utilized the below tools and technologies:
- Quartz 2.2.1
- Spring Framework 3.2.12
- jQuery recurrence widget (recurrenceinput.js)
- Google’s iCalendar RFC 2445
Conclusion
By and large, Quartz Scheduler has gained massive popularity among Java developers due to its flexibility and dynamic scheduling capabilities. No wonder, it is one of the most preferred job schedulers for dynamic job scheduling. I assume this blog would help Java developers to gain a good understanding of Quartz Scheduler for dynamic job scheduling. If you have any queries or inputs, please feel free to post your comments.
Author
Bala Gangadhar Tilak Mamidipalli is a Java programmer at Evoke Technologies. He has 14 years of experience in designing and developing client server and web based applications using Java and J2EE technologies. Tilak likes reading about new technologies during his free time. |
74 Comments
Nice blog, helpful for dynamic schedules using RRule and quartz
thank you Shiva DG
It helps in understanding clearly about the scheduling mechanisms using Quartz and Google’s RRULE. Thanks for sharing the details, nice blog.
thank you Kiran
Useful blog for dynamic scheduling using Quartz jobs,Thanks for posting .
thank you Siva Kumar
Nice blog!! Is the custom logic for converting rrule to cron expression generic? If YES, It can be published as a reusable component. Thanks.
Yes Sravan, it is possible to make it as a re-usable component with certain limitations. But I feel quartz should provide the support for iCalendar RFC2445 integration. I think Terracotta would be addressing this issue in near future. https://jira.terracotta.org/jira/browse/QTZ-252
Sravan, below is the generic code for converting rrule to cron expression but as mentioned earlier, quartz supports different triggers not just cron so we need a generic implementation from quartz api to integrate quartz with rrule ical.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import com.google.ical.values.RRule;
import com.google.ical.values.WeekdayNum;
public class RRuleToCronExpressionConverter {
private static final String START_TIME = “startTime”;
private static final String MONTH = “1/%s”;
private static final String INTERVAL = “INTERVAL”;
private static final String HASH = “#”;
private static final String QUESTION_MARK = “?”;
private static final String ASTERISK = “*”;
private static final String SPACE = ” “;
private static final int CRON_BUILDER_CAPACITY = 50;
private static final String LAST_DAY_OF_MONTH = “L%d”;
private static final int DAY_OF_WEEK_BUILDER_CAPACITY = 20;
private static final SimpleDateFormat HOUR_MIN_FORMAT = new SimpleDateFormat(“h:mm a”, Locale.getDefault());
@SuppressWarnings(“serial”)
private static final Map WEEK_MAP = new HashMap() {
{
put(“SU”, “SUN”);
put(“MO”, “MON”);
put(“TU”, “TUE”);
put(“WE”, “WED”);
put(“TH”, “THU”);
put(“FR”, “FRI”);
put(“SA”, “SAT”);
}
};
private Calendar getCalendar(final String startTime) {
Calendar calendar = Calendar.getInstance();
try {
calendar.setTime(HOUR_MIN_FORMAT.parse(startTime));
}
catch (ParseException e) {
e.printStackTrace();
}
return calendar;
}
String getCronExpression(final RRule rRule) {
StringBuilder cronExpressionBuilder = new StringBuilder(CRON_BUILDER_CAPACITY);
Calendar calendar = getCalendar(START_TIME);
cronExpressionBuilder.append(getSeconds(rRule)).append(SPACE).append(calendar.get(Calendar.MINUTE)).append(SPACE)
.append(calendar.get(Calendar.HOUR_OF_DAY)).append(SPACE);
switch (rRule.getFreq()) {
case DAILY:
cronExpressionBuilder.append(ASTERISK).append(SPACE).append(ASTERISK).append(SPACE).append(QUESTION_MARK).append(SPACE);
break;
case WEEKLY:
cronExpressionBuilder.append(QUESTION_MARK).append(SPACE).append(ASTERISK).append(SPACE).append(getDayOfWeek(rRule))
.append(SPACE);
break;
case MONTHLY:
cronExpressionBuilder.append(getDayOfMonth(rRule)).append(SPACE).append(getMonth(rRule)).append(SPACE)
.append(getDayOfWeek(rRule)).append(SPACE);
break;
case YEARLY:
cronExpressionBuilder.append(getDayOfMonth(rRule)).append(SPACE).append(getMonth(rRule)).append(SPACE)
.append(getDayOfWeek(rRule)).append(SPACE);
break;
default:
break;
}
cronExpressionBuilder.append(ASTERISK);
return cronExpressionBuilder.toString();
}
private String getDayOfMonth(final RRule rRule) {
String dayOfMonth = QUESTION_MARK;
if (ArrayUtils.isNotEmpty(rRule.getByMonthDay())) {
if (rRule.getByMonthDay()[0] < 0) {
dayOfMonth = String.format(LAST_DAY_OF_MONTH, rRule.getByMonthDay()[0]);
}
else {
dayOfMonth = String.valueOf(rRule.getByMonthDay()[0]);
}
}
return dayOfMonth;
}
private String getDayOfWeek(final RRule rRule) {
String dayOfWeek = QUESTION_MARK;
List weekdayNums = rRule.getByDay();
if (CollectionUtils.isNotEmpty(weekdayNums)) {
StringBuilder weeks = new StringBuilder(DAY_OF_WEEK_BUILDER_CAPACITY);
for (WeekdayNum weekdayNum : weekdayNums) {
weeks.append(“,”).append(WEEK_MAP.get(weekdayNum.wday.name()));
if (weekdayNum.num != 0) {
weeks.append(HASH).append(weekdayNum.num);
}
}
dayOfWeek = weeks.substring(1);
}
return dayOfWeek;
}
private String getMonth(final RRule rRule) {
String month = null;
if (rRule.toIcal().contains(INTERVAL)) {
month = rRule.getInterval() > 0 ? String.format(MONTH, rRule.getInterval()) : String.format(MONTH, 1);
}
else if (ArrayUtils.isNotEmpty(rRule.getByMonth())) {
month = String.valueOf(rRule.getByMonth()[0]);
}
return month;
}
private int getSeconds(final RRule rRule) {
int seconds = 0;
if (ArrayUtils.isNotEmpty(rRule.getBySecond())) {
seconds = rRule.getBySecond()[0];
}
return seconds;
}
Nice blog Tilak. Its gives more information about the scheduling mechanism using Quartz and RRULE.Thanks for posting.
thank you Giri
Nice and very helpful article. superb material to get the required info on Quartz. Thanks for posting.
thank you Venu
This is like a hidden thing which come out through this blog thanks for sharing and this is useful to developers for dynamic schedules using RRule and quartz in projects.
thank you Ashok.
Nice post with a clear explanation about the Quartz Job Scheduling technology for the beginners.
Thank you for the sharing and expecting more in near future.
Thanks…!!
It is a great post with step by step explanation, keep up your good work.
Very nice article, Good job!
Nice Article. Can you please provide me the source code of this application.
Thanks
Hi Ramalinga Reddy, This project is quite huge one. I will try to setup a small maven project and share it with you. Thanks for your comment.
Hi Tilak,
Thanks for the wonderful post. I have been looking for this. Can you please share the source code. It would be really helpful.
Hi Sneha,
Due to security reasons i can not share the code base with you but i can definitely help you in implementing this feature.
Interesting article ! I was enlightened by the info ! Does someone know if my assistant would be able to obtain a fillable 2014 IRS 1040 – Schedule A form to fill out ?
Hello Sir, your article is very nice. But can you send me small Quartz maven project with all these(Start, Stop, Resume, Pause) operations
Hi Pradeep,
thq for the feedback. please take a look at the sample maven app contains your requested actions.
Hi Pradeep,
i was unable to attach files to comments, pl send me your email id sop that i can send you the sample maven project.
Hi Tilak,
Thanks a lot for your Post.
I have One Query regarding memory Overhead Of multiple Scheduled task.
will it affect the memory, if we have scheduled more than thousand jobs at a time.
Hi Tanweer,
It does affect the memory when more no.of jobs are scheduled to run at a time so we need to be cautious about this and tune the thread pool count according to our need. We can throttle the thread pool count dynamically based on our need without restarting the server. Please let me know if you have further comments.
Nice blog Tilak. Need a sample code for UI and how to pass the RRule to controller.
Hi kannabiran,
Please send me your email id so that i can send sample UI code for reference.
your tutorial is very nice.. if possible can u share the source code to my email. thanks..
Nice tutorial dude..
can you share this tutorial project to my email?
email : jeffrychristian1@gmail.com
Thanks..~
Very nice blog.
I have kind of a similar scenario to work upon.
I want to implement a scheduler, in which one thread will continuously listen to a mysql/oracle database table. Once a new record is inserted into the database table, depending upon one of the column value of my database table, a new thread will be spawned correspondingly in my scheduler which will run periodically.
Any ideas how can I use quartz in this ?
very nice tutorial ..
can you please share this tutorial project to my email?
email : chaurasia.akhilesh@gmail.com
Thanks,
Akhilesh
Hi Tilak,
Nice tutorial. It would be kind of you if you could mail the source code at zaheer032@gmail.com
Could you please share the code with me?
send the code please
Hi Tilak,
A job is scheduled to fire after 10 secs. Quartz Scheduler automatically unschedules the job before invoking the fire() method. So jobs are not getting executed. This issue seems to happen if we continuously schedule jobs (like more than 10-15 jobs). After 10-15 jobs jobs, no other jobs are getting fired.
Can you please let me know under what and all situations Quartz Scheduler will unschedule ? This seems to be an abnormal behavior.
NOTE: We didn’t invoke unschedule any where in our code unless and until it is required. Also, schedules are not deleted manually.
Please suggest if you have idea.
Hi tilak, could please mail me the project which covers pause/resume, edit and delete
arshfrndz(at)yahoo(dot)com
Hi Tilak,
I am developing Content Management System Project in Springs and hibernate which includes sending auto mails.
Can you suggest me with some sample code of Quartz such that i can explore and implement it as my requirement.
Please mail me at naveenreddy531cse(at)gmail(dot)com
Sent, please check your email.
Great article. Thank you for posting. Can you please send the source code psaidya(at)gmail(dot)com?
Here you go.
Hi, Your article is very nice and helpful.
Could you please share the code with me sampath(at)edify(dot)in ?
Nice blog and Thank you for a very informative post Tilak. Can you please share the code with me, my email id is rakeshreddy6843(at)gmail(dot)com
Hi,
Do you have a sample project on Spring boot which should use quartz scheduler for scheduling job(>1) and job related details will be in .yml file. Basically, how to trigger a job from spring boot application. Any working code will help me a lot.
Thanks in advance.
Hi,
Can you please share your Dynamic Job Scheduling Using Quartz Scheduler code with me?
My email id is renukamjadhav(at)gmail(dot)com
Thanks!
Very nice article. Please share the code base. My email id is onlypankajsharma(at)gmail(dot)com
Nice article.Could you please share the code?My email id is anoopc444(at)gmail(dot)com
Nice blog,very helpful for me sir.PLease can you send me your source code
my email @: wajdibhh(at)gmail(dot)com
thks in advance
Hi
Thanks for the informative post. Can I validate if the task execution time is updated everytime it is called, and reschedule it during the call? So all the tasks details are saved in DB at my end and the db entries can be updated from a different web based app.
Thus, I will have to reschedule jobs on the fly based on the entries in database. (Maybe using a flag in db, so that I know which one is updated)
Hi Tilak,
Nice Article!!!
Can you share sample code on email : kadav.kiran(at)gmail(dot)com or any repository location if it anywhere on GIT or SVN.
Hi Bala,
I am designing similar scheduling. Could you please share the code with me if possible so I need not work much on this.
mail id: Sanjeeva.potru(at)gmail(dot)com
Thanks,
Sanjeeva Reddy
Please Send Me a UI Sample Code EmailId hardikmaster4(at)gmail(dot)com
Excellent work. You can pass your example.
Thank you.
my email is bravoaugusto300(at)hotmail(dot)com.
Could you please share some sample code with UI for reference. my mail id : v(dot)krishna(dot)kalluri(at)gmail(dot)com
Or else please provide an option to download some sample UI code.
Hi Krishna,
Did you get the code if you got it can you please send it to me. my mail id sindhu2953(at)gmail(dot)com
Could you please share some sample code
Its really helpful for me. thank you for the blog. could you please share me sample code please my mail id sindhu2953(at)gmail(dot)com.
HI Tilak
Could you provide the sample code with ui . Send me on my email Id Ask.kaurav(at)gmail(dot)com
Nice blog Tilak. Please share sample code to nguyenanhtiep(at)gmail(dot)com. Thanks you!!!
Great and nice Lesson. Please can you send me source code to kersyduru@gmail.com. Thanks so much .
HI Tilak
I like your tutorial very helpful content.
Could you provide the sample code Send me on my email Id aakash.narla.rao@gmail.com
Hi Tilak,
Thanks for your tutorial.It helps a lot to me.If possible to share your code to any code repository or please send it my email( rajwan@daffodil.ac).
Great article. Thank you for posting. Can you please send the source code ajayboed@hotmail.com?
Hi Tilak, Thanks for your code tutorial. please, send the source code to my email : wcleedawon@gmail.com
thanks!!
Thanks for the article, Please can you send the sample code to my email id :: mohammed.maheboobpatel@gmail.com
Great article. Thank you ^^
please, send the source code to my email : parkys0620@gmail.com
Thank you ^^
can you please send me the source code of RRule to corn expression convertar???
I desperately need this.
my email address: saurojit14@gmail.com
Hi Bala,
Great article. May you please share the code to my email: dchawla8639@gmail.com
Hi Bala,
Thanks for this great article. May you please share the code, especially the source code for converting RRULE to cron expression?
great sample my friend, plz share code to my email: caotrananh@gmail.com