I was looking for a way to create Cron jobs in Worker Roles on Windows Azure and I found Quartz.Net. A Nuget package which is still being maintained as of January 2013. The documentation wasn’t great and was mostly out of date. Furthermore the API seems to have evolved quite a bit over time. The framework seems quite capable and very flexible. I’m barely using any of its potential at the moment! It has schedules and triggers, with a better understanding of its functionality, I would probably grant it more responsibility in my workflow.
The following is an example that demonstrates how I was able to successfully schedule jobs.
Start by implementing the IJob interface to create a job that can be managed by Quartz.Net.
public class DailyJob : IJob { public void Execute(IJobExecutionContext context) { //Do your daily work here } }
Then in the RoleEntryPoint OnStart() method create and configure the scheduler with a trigger and the daily job. This is the part that was greatly lacking in documentation. To get this working I had to poke around the available methods and objects using IntelliSense. Once you have created the scheduler, be sure to keep a reference to it in your Worker Role instance. This will ensure that your jobs execute.
public class WorkerRole : RoleEntryPoint { public override void Run() { //default project template implementation while (true) { Thread.Sleep(10000); Trace.WriteLine("Working", "Information"); } } public override bool OnStart() { ServicePointManager.DefaultConnectionLimit = 12; ConfigureScheduler(); return base.OnStart(); } public override void OnStop() { sched.Shutdown(false); sched = null; base.OnStop(); } IScheduler sched; private void ConfigureScheduler() { var schedFact = new StdSchedulerFactory(); sched = schedFact.GetScheduler(); var job = new JobDetailImpl("DailyJob", null, typeof(DailyJob)); var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); var cronScheduleBuilder = CronScheduleBuilder.DailyAtHourAndMinute(17, 15) .InTimeZone(timeZoneInfo); var trigger = TriggerBuilder.Create() .StartNow() .WithSchedule(cronScheduleBuilder) .Build(); sched.ScheduleJob(job, trigger); sched.Start(); } }
When configuring a time based job, its quite important to keep in mind that all Windows Azure servers utilize UTC time, and ‘en-US’ locale settings. It’s imperative that you make sure that your job is scheduled to execute in the right time zone. Use TimeZoneInfos to get the correct time zone info object.
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); var cronScheduleBuilder = CronScheduleBuilder.DailyAtHourAndMinute(17, 15) .InTimeZone(timeZoneInfo); var trigger = TriggerBuilder.Create() .StartNow() .WithSchedule(cronScheduleBuilder) .Build();
Time Zone IDs recognized by .NET
Time Zone ID | Time Zone Display Name |
Morocco Standard Time | (GMT) Casablanca |
GMT Standard Time | (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London |
Greenwich Standard Time | (GMT) Monrovia, Reykjavik |
W. Europe Standard Time | (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna |
Central Europe Standard Time | (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague |
Romance Standard Time | (GMT+01:00) Brussels, Copenhagen, Madrid, Paris |
Central European Standard Time | (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb |
W. Central Africa Standard Time | (GMT+01:00) West Central Africa |
Jordan Standard Time | (GMT+02:00) Amman |
GTB Standard Time | (GMT+02:00) Athens, Bucharest, Istanbul |
Middle East Standard Time | (GMT+02:00) Beirut |
Egypt Standard Time | (GMT+02:00) Cairo |
South Africa Standard Time | (GMT+02:00) Harare, Pretoria |
FLE Standard Time | (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius |
Israel Standard Time | (GMT+02:00) Jerusalem |
E. Europe Standard Time | (GMT+02:00) Minsk |
Namibia Standard Time | (GMT+02:00) Windhoek |
Arabic Standard Time | (GMT+03:00) Baghdad |
Arab Standard Time | (GMT+03:00) Kuwait, Riyadh |
Russian Standard Time | (GMT+03:00) Moscow, St. Petersburg, Volgograd |
E. Africa Standard Time | (GMT+03:00) Nairobi |
Georgian Standard Time | (GMT+03:00) Tbilisi |
Iran Standard Time | (GMT+03:30) Tehran |
Arabian Standard Time | (GMT+04:00) Abu Dhabi, Muscat |
Azerbaijan Standard Time | (GMT+04:00) Baku |
Mauritius Standard Time | (GMT+04:00) Port Louis |
Caucasus Standard Time | (GMT+04:00) Yerevan |
Afghanistan Standard Time | (GMT+04:30) Kabul |
Ekaterinburg Standard Time | (GMT+05:00) Ekaterinburg |
Pakistan Standard Time | (GMT+05:00) Islamabad, Karachi |
West Asia Standard Time | (GMT+05:00) Tashkent |
India Standard Time | (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi |
Sri Lanka Standard Time | (GMT+05:30) Sri Jayawardenepura |
Nepal Standard Time | (GMT+05:45) Kathmandu |
N. Central Asia Standard Time | (GMT+06:00) Almaty, Novosibirsk |
Central Asia Standard Time | (GMT+06:00) Astana, Dhaka |
Myanmar Standard Time | (GMT+06:30) Yangon (Rangoon) |
SE Asia Standard Time | (GMT+07:00) Bangkok, Hanoi, Jakarta |
North Asia Standard Time | (GMT+07:00) Krasnoyarsk |
China Standard Time | (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi |
North Asia East Standard Time | (GMT+08:00) Irkutsk, Ulaan Bataar |
Singapore Standard Time | (GMT+08:00) Kuala Lumpur, Singapore |
W. Australia Standard Time | (GMT+08:00) Perth |
Taipei Standard Time | (GMT+08:00) Taipei |
Tokyo Standard Time | (GMT+09:00) Osaka, Sapporo, Tokyo |
Korea Standard Time | (GMT+09:00) Seoul |
Yakutsk Standard Time | (GMT+09:00) Yakutsk |
Cen. Australia Standard Time | (GMT+09:30) Adelaide |
AUS Central Standard Time | (GMT+09:30) Darwin |
E. Australia Standard Time | (GMT+10:00) Brisbane |
AUS Eastern Standard Time | (GMT+10:00) Canberra, Melbourne, Sydney |
West Pacific Standard Time | (GMT+10:00) Guam, Port Moresby |
Tasmania Standard Time | (GMT+10:00) Hobart |
Vladivostok Standard Time | (GMT+10:00) Vladivostok |
Central Pacific Standard Time | (GMT+11:00) Magadan, Solomon Is., New Caledonia |
New Zealand Standard Time | (GMT+12:00) Auckland, Wellington |
Fiji Standard Time | (GMT+12:00) Fiji, Kamchatka, Marshall Is. |
Tonga Standard Time | (GMT+13:00) Nuku’alofa |
Azores Standard Time | (GMT-01:00) Azores |
Cape Verde Standard Time | (GMT-01:00) Cape Verde Is. |
Mid-Atlantic Standard Time | (GMT-02:00) Mid-Atlantic |
E. South America Standard Time | (GMT-03:00) Brasilia |
Argentina Standard Time | (GMT-03:00) Buenos Aires |
SA Eastern Standard Time | (GMT-03:00) Georgetown |
Greenland Standard Time | (GMT-03:00) Greenland |
Montevideo Standard Time | (GMT-03:00) Montevideo |
Newfoundland Standard Time | (GMT-03:30) Newfoundland |
Atlantic Standard Time | (GMT-04:00) Atlantic Time (Canada) |
SA Western Standard Time | (GMT-04:00) La Paz |
Central Brazilian Standard Time | (GMT-04:00) Manaus |
Pacific SA Standard Time | (GMT-04:00) Santiago |
Venezuela Standard Time | (GMT-04:30) Caracas |
SA Pacific Standard Time | (GMT-05:00) Bogota, Lima, Quito, Rio Branco |
Eastern Standard Time | (GMT-05:00) Eastern Time (US & Canada) |
US Eastern Standard Time | (GMT-05:00) Indiana (East) |
Central America Standard Time | (GMT-06:00) Central America |
Central Standard Time | (GMT-06:00) Central Time (US & Canada) |
Central Standard Time (Mexico) | (GMT-06:00) Guadalajara, Mexico City, Monterrey |
Canada Central Standard Time | (GMT-06:00) Saskatchewan |
US Mountain Standard Time | (GMT-07:00) Arizona |
Mountain Standard Time (Mexico) | (GMT-07:00) Chihuahua, La Paz, Mazatlan |
Mountain Standard Time | (GMT-07:00) Mountain Time (US & Canada) |
Pacific Standard Time | (GMT-08:00) Pacific Time (US & Canada) |
Pacific Standard Time (Mexico) | (GMT-08:00) Tijuana, Baja California |
Alaskan Standard Time | (GMT-09:00) Alaska |
Hawaiian Standard Time | (GMT-10:00) Hawaii |
Samoa Standard Time | (GMT-11:00) Midway Island, Samoa |
Dateline Standard Time | (GMT-12:00) International Date Line West |
Summary
Event though Quartz.Net had documentation that wasn’t great and that it was mostly out of date, I recommend taking a closer look. The framework seems quite capable and very flexible. It has schedules, triggers and a few other functionalities, with a better understanding of its functionalities, I would probably grant it more responsibility in my workflow.
Nice post! Have you thought about using some sort of concurrency check if you have more than 1 worker? Blob lease? Would be interested in your thoughts.
LikeLike
Thanks, actually that was the next step. At the moment, my jobs are hosted on a node that is responsible for persisting data to SQL Database and since it doesn’t require any scaling, I’ve been putting it off for a while. If your architecture is composed of worker roles who are designed to scale out. Blob leases are a great way to go. But I think there may be a need for some kind of strategy when there is a need to distribute tasks or jobs evenly over many Role instances.
I think this would make for a great blog topic.
LikeLike
What did you find the CPU utilization was when using Quartz.NET? How much overhead did Quartz.NET take up in monitoring the schedules?
LikeLike
It’s barely noticeble. My Extra Small virtual machine instances on Windows Azure report 0.13% on idle time and i’ve got a few other processes that aren’t in Quartz.Net.
I also created a scheduler in my personal tools that allows me to configure basic times schedules for daily tasks.
I will probably post about it soon, the code is available on GitHub, JobSchedule.cs. It allows me to configure the schedules from the Cloud Configuration instead of hard coding it.
As you can see there is a lot of room for refactoring…
LikeLike
Hi Alexandre,
How about when we are using quartz with multiple instances. If one instance that schedules the job goes down, how will the other instances maintain it. Because if one instance goes down then the triggers of that instance also goes down.
So how to make use of windows azure feature.
LikeLike
Hi Rajat,
You have found the drawback to this method. I did not come across this issue, because I usually run my tasks twice a day. if the first fails the second will pickup the slack.
scheduling tasks using any scheduler will probably give you the same problem.
In this case I would recommend looking into using queues which are able to recover from this type of failure.
LikeLike
Hi Alexandre,
My question is if the instance that creates the scheduler object goes down or gets deleted will
the further jobs get scheduled if yes who will handle those jobs.
Because what I did is:
1) I have a worker role in windows azure that takes the jobs from the queue that are been put to queue by web role. And i have many instances of the worker role, any instance may pick up the job and schedule it.
2) Now the problem is: Assume job1 is picked by instance1 and job2 is picked by instance2 and now at some point of time the instance2 gets deleted or goes down. Then the job2 that is assigned to instance2 (job2 scheduled by instance2) how will it continue to schedule the remaining tasks periodically.
Do we have some facility in quartz so that we can redirect the job to some other instance in the deployment. In other words how we can take the advantage of windows azure cloud.
LikeLike
Hi Jajat,
You’ve got an excellent challenge there, because you have a few key questions in there.
First there is a need to figure out if the Worker Role has recycled, or if it was taken down for maintenance. Has the Worker Role failed over? Has the Worker Role been able to execute code when it stopped?
Then you also need to inspect how you are tracking jobs. I’m not sure if the queue is the best solutions here. It may be part of a greater solution depending on the number of jobs that need to be scheduled for specific times.
I found this question on stackoverflow about a stateful schedule http://stackoverflow.com/questions/6503780/quartz-net-job-storage-query
IMO, this is more along the lines of what you need, because when the Role fails over it will read its configuration from the store and rebuild itself. a queue can be used to store jobs before you add them to the stateful schedule.
On NuGet you also have a project that provides a stateful schedules
Using MongoDB https://nuget.org/packages/quartz.impl.mongodb/
You could also implement your own data store using Windows Azure Table Storage to keep a stateful schedule.
These solutions are simpler than trying to figure out which task has or has not run and detecting if the Worker Role responsible for hosting Quartz is down, recycling or failing over.
Let me know if this helps
Alex
LikeLike
Hi Alex,
That is a great suggestion,
Sorry for disturbing you with too many questions.
I have a small doubt about quartz. I am using ADOJob store quartz mechanism. Here since
the jobs and triggers are stored in database, but there might be something stored on the
primary memory and flushing of which will result in the loss of scheduler right…?
Thanks
-Rajat
LikeLike
Hi Alex,
That is a great suggestion,
Sorry for disturbing you with too many questions.
I have a small doubt about quartz. I am using ADOJob store quartz mechanism. Here since
the jobs and triggers are stored in database, but there might be something stored on the
primary memory and flushing of which will result in the loss of scheduler right…?
Thanks
-Rajat
LikeLike
Hi Rajat,
Forgive me for the delay, I recently started a new mandate and I haven’t been around as much as I would have liked.
I must admit that I am not very familiar with the inner workings of ADOjob store for Quartz. I have seen people talk about a data store using Table Storage but I haven’t been able to find it. I was hoping to have time to implement one this week but time simply wasn’t there..
As for your question, my personal hunch is that yes, there is always a possibility of losing some state when a server goes down. But hopefully it should not be significant.
To validate this, some tests should be done, any results would be very interesting.
I recommend visiting https://github.com/quartznet/quartznet/issues and ask them directly.
LikeLike
I’m wondering if the while (true) { Thread.Sleep(1000) } method is required to be in the Run method.
LikeLike
Hi,
In this specific case, it is required because it blocks the Run method from returning.
If this method returns, the Role is forced to recycled.
LikeLike
Have you tried to use exporter service of quartz ?? I am trying to use quartz with worker role multiinstace.
But i want connect to exporter service to get all jobs etc..
LikeLike
Hi, I have hosted the Quartz.Net as Windows Service in azure worker role, Now as per the SLA with Microsoft we need to make at least two instances of every worker and web role, We have used Quartz 1.8 version. as per my understanding Quartz 1.8 not have Multiple Scheduler functionality. can i use latest version of Quartz and accomplish my requirement where i can create two instances of Quartz service from single worker role and with SAME database instance
LikeLike
Hi, I haven’t followed up on the latest developments around Quartz. In the past I build my own double schedule to mitigate failure issues (https://alexandrebrisebois.wordpress.com/2013/08/21/dealing-with-worker-role-failovers-by-scheduling-duplicate-jobs/). If you have the ability to use a database that is shared, than you need to find a way to identify non completed and failed jobs and restart them. Using a service like Azure Scheduler, Azure Batch, Azure Automation, Azure Web Jobs or Azure Logic App can help you with these complication scenarios. These services are built to be HA and to retry on failure.
LikeLike
You should consider a follow-up post showing how to make this controllable remotely. (Right now it’s a stand-alone isolated instance.)
LikeLike
so how do i built it (worker roles) to the Azure ?
LikeLike