It is likely you will be challenged with a project to build one or more scheduled jobs, which are services that run in the background to perform long-running activities or tasks without user interaction. In this post, we will introduce an open source job scheduling system – Quartz.NET. It is a clean design for a developer to implement and provides many ready-to-use powerful features. You can visit http://quartznet.sourceforge.net/ to review the documentation and download.

I would suggest reading the tutorial and documentation, so you are familiar with all features. This article will focus on the hosting options with an introduction to the core features. The following is an overview of the key Quartz.NET concepts.

  • Scheduler – create an instance of the scheduler
  • Job – an IJob implementation containing the Execute method invoked by the scheduler
  • Trigger – defines the firing of a job, which is the scheduler component

This is a design that follows separation of concerns, since the job is not coupled to the trigger/schedule. This provides the flexibility to configure a job to participate in one or more schedules.

So…let’s take a look at a very simple job implementation.

1
    public class MyJob : IJob
2
    {
3
        public void Execute(IJobExecutionContext context)
4
        {
5
            Console.WriteLine("MyJob is executing...");
6
        }
7
    }
8
}

The context parameter contains the properties and JobDataMap, which enables you to pass information to the job. The following is an example.

1
// create the job info
2
JobDetail jobDetail = new JobDetail("MyJob", null, typeof(MyJob));
3
 
4
//set the job data map collection 
5
jobDetail.JobDataMap["message"] = "Testing";
6

The following is the updated MyJob Execute method extracting the JobDataMap value.

1
        public void Execute(IJobExecutionContext context)
2
        {
3
            JobDataMap dataMap = context.JobDetail.JobDataMap;
4
            string message = dataMap.GetString("message");
5
            Console.WriteLine(message);
6
        }
7

The next step is creating an instance of the scheduler, so we can execute the jobs. You can create an instance of the scheduler programmatically.

1
// create a scheduler factory
2
ISchedulerFactory factory = new StdSchedulerFactory();
3
 
4
// create scheduler and start
5
IScheduler scheduler = factory.GetScheduler();
6
scheduler.Start();
7

This start-up process can also be managed using a Windows service, which is our first option for hosting the Quartz Scheduler. It’s convenient that the system provides an out-of-the-box service, so you just install the available service. You will find the service or Quartz Server is located under the server folder with the appropriate .NET version. The following is a screenshot of the install command and process, so the Quartz Server is registered as a Windows Service.

Quartz Server Install

Quartz Server Install

Please remember to run the install as Administrator and you should also make sure the exe is Unblocked, which will cause installation issues. If the install is successful the Quartz Server should appear in your Services list. Just set the appropriate user and start the service. The service is setup to create event log entries, so you can check the status with the Event Viewer.

The final step is wiring the scheduler, job and triggers. We have the scheduler running and the job defined, but now we need to setup a trigger. You have a choice of several triggers – including the simple, calendar and cron trigger. In this example, we will configure the job to fire at a specified time every day. We will setup the Quartz Server configuration file, which provides the ability to define jobs and triggers. You could also programmatically configure, but we already have the Windows service hosting the scheduler. The following is the quartz_jobs.xml file, which provides the configuration for the service.

01
<?xml version="1.0" encoding="UTF-8"?>
02
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
03
 
04
  <processing-directives>
05
    <overwrite-existing-data>true</overwrite-existing-data>
06
  </processing-directives>
07
 
08
  <schedule>
09
    <job>
10
        <name>MyJob</name>
11
        <group>MyGroup</group>
12
        <description>Job for Quartz Server</description>
13
        <job-type>Quartz.Jobs.MyJob, Quartz.Jobs</job-type>
14
        <durable>true</durable>
15
        <recover>false</recover>
16
    </job>
17
 
18
    <trigger>
19
 <cron>
20
         <name>CronTrigger</name>
21
         <group>CronTriggerGroup</group>
22
         <description>Trigger to to first job at 12:45</description>
23
         <job-name>MyJob</job-name>
24
         <job-group>MyGroup</job-group>
25
         <misfire-instruction>SmartPolicy</misfire-instruction>
26
                <cron-expression>0 45 12 * * ?</cron-expression>
27
        </cron>
28
    </trigger>
29
  </schedule>
30
</job-scheduling-data>

The wiring is much clearer with the above configuration file. The schedule section contains job and trigger definitions. The job definition contains several properties, but job-type defines the target IJob implementation. The job-name and job-group are references, so the trigger can identify the target job for execution. In this example, we are defining a cron trigger to execute the job at 12:45pm. The cron-expression contains the following space delimited values.

  • Seconds
  • Minutes
  • Hours
  • Day of Month
  • Month
  • Day of Week
  • Year (optional)

This is a very flexible trigger, so you can schedule jobs to execute based on a variety of values. For example: if you would like the job to run on weekdays then set the “Day of Week” value to “MON-FRI”. As you explore the options, you should find a trigger option that will satisfy your requirements.

So…this is a quick overview of the core Quartz.NET features and hosting the scheduler as a Windows service. In the next post, I will provide the steps to host under IIS using the Spring.NET IoC container. This option offers a few advantages including simplified configuration and invoking non-Job service methods.

I hope this article provides an overview and quick start for establishing a .NET job scheduler, so you are not forced to write the plumbing code to perform the same tasks.