How to create a multi-task Azure Worker Role with Quartz.net

A short tutorial on how to use Quartz.net to implement a mutli-task Worker Role on Azure.

Back to blog

What is a Worker Role ?

A ‘Worker Role’ is a type of Azure application (or cloud service in Azure terminology) that is typically used for long running background tasks that don’t require user interaction – think Windows Service for the cloud. Technically, it’s a dedicated Azure VM running the Azure runtime environment and your Worker Role application.  For Worker Role VMs, IIS is disabled by default.

What do Worker Roles cost ?

Microsoft charges the standard per hour VM rate for each Worker Role instance you deploy – note that’s not per hour as in the actual time the VM is active and doing something, but ‘per hour’ as in every hour it is live on the Azure platform. Currently, the cheapest VM instance works out at 2 cents per hour or about $14 dollars per month.

Why is this a problem ?

A common use case for a web application is to have multiple background tasks that run infrequently and don’t require much resource – for db maintenance or report production for example. So although the 2 cents per hour doesn’t sound a lot, it obviously doesn’t make sense to create and deploy a Worker Role for each task where that Worker Role is backed by a full instance of Server 2008 – the average utilization for the VM would be < 1% but you would be paying for 100%. There would also be overheads to managing so many Worker Roles.

What is the solution ?

The obvious solution is to build a ‘multi-task’ Worker Role – i.e. one Worker Role that runs different types of tasks on a pre-defined schedule.

There are a number of approaches for building a multi-task Worker Role – for example, you can manually spin up worker threads or TPL tasks with a long Thread.Sleep at the end of every iteration.

A better approach is to use a job scheduler to run timed jobs – you have to write less plumbing code and its easy to specify how often a task should run as the timings can be specified using CRON expressions. CRON expressions also allow you to easily specify complex timing operations (for example, ‘the second Tuesday of every month at 10pm’) if that is something you ever need to do.

The most robust open-source scheduler for .NET is Quartz.net – a direct port of the Java Quartz scheduler.

You can do a lot with Quartz.net, but the basics of setting it up to run scheduled jobs in a Worker Role is straightforward.

Creating a Quartz.net Worker Role

Lets assume we have a database maintenance job that we want to run every hour.  To do this with Quartz, we define,

  1. A class that implements the job – in this case it would, for example, connect to the db and run some maintenance stored procedures.
  2. A trigger – triggers are fired by Quartz on a schedule that you define.  Each trigger in turn executes one or more jobs.
  3. A scheduler – a set of triggers managed by Quartz

Running through it step by step,

First, create a Worker Role project and add Quartz.net to the project via NuGet (the package name is Quartz).

Next define the  job – the simplest type of Quartz jobs are classes that implement the IJob interface. IJob declares a single method, Execute(IJobExecutionContext context). Quartz.net calls the Execute method each time it fires a trigger  that executes the job.

Finally, initialize Quartz in the OnStart method of your RoleEntryPoint. This involves setting up the scheduler and loading the jobs and triggers. The code below creates triggers for the job programmatically and schedules the job to run once every hour.

That is basically it. Deploy to Azure and your task will run every hour.

Although this is a very simple implementation that barely scratches the surface of what you can do with Quartz.net, you can see that declaratively declaring jobs and timings is much cleaner and simpler that manually spinning up and managing multiple threads.

Moving the scheduling into an external config file would allow you to modify the timings and switch off jobs without having to redeploy.

As you read this far, you should follow me on twitter here.