Search
Close this search box.

Quartz.Net Writing your first Hello World Job

In this blog post I’ll be covering,

  • 01: A few things to consider before you should schedule a Job using Quartz.Net
  • 02: Setting up your solution to use Quartz.Net API
  • 03: Quartz.Net configuration
  • 04: Writing & scheduling a hello world job with Quartz.Net
  • 05: Download Quartz.Net sample project and instructions

If you are new to Quartz.Net I would recommend going through,

01 – A few things to consider before you should schedule a Job using Quartz.Net

To schedule a job to run on Quartz.Net windows service at the very minimum you need the 3 items listed below,

    – An instance of the scheduler service

    – A trigger

    – And last but not the least a job

But a few additional things that you should think about are… For example, if I wanted to schedule a script to run on the server, I should be jotting down answers to the below questions,

 a. Considering there are multiple machines set up with Quartz.Net windows service, how can I choose the instance of Quartz.Net where I want my script to be run

     b. What will trigger the execution of the job

     c. How often do I want the job to run

     d. Do I want the job to run right away or start after a delay or may be have the job start at a specific time

     e. What will happen to my job if Quartz.Net windows service is reset

     f. Do I want multiple instances of this job to run concurrently

     g. Can I pass parameters to the job being executed by Quartz.Net windows service

02 – Setting up your solution to use Quartz.Net API

1. Create a new C# Console Application project and call it “HelloWorldQuartzDotNet” and add a reference to Quartz.Net.dll. I use the NuGet Package Manager to add the reference. This can be done by right clicking references and choosing Manage NuGet packages, from the Nuget Package Manager choose Online from the left panel and in the search box on the right search for Quartz.Net. Click Install on the package “Quartz” (Screen shot below).

image

Figure – Adding Quartz.Net reference to my project via Nuget Package Manager

SNAGHTML3af4a28b

Figure – Searching for Quartz.Net reference in Nuget Package Manager

image

Figure – Quartz reference added to my project via Nuget Package Manager

2. Right click the project and choose Add New Item. Add a new Interface and call it ‘IScheduledJob.cs’. Mark the Interface public and add the signature for Run. Your interface should look like below.

namespace HelloWorldQuartzDotNet
{
    public interface IScheduledJob
    {
        void Run();
    }
}

3. Right click the project and choose Add new Item. Add a class and call it ‘Scheduled Job’. Use this class to implement the interface ‘IscheduledJob.cs’. Look at the pseudo code in the implementation of the Run method.

using System;

namespace HelloWorldQuartzDotNet
{
    class ScheduledJob : IScheduledJob
    {
        public void Run()
        {

            // Get an instance of the Quartz.Net scheduler

            // Define the Job to be scheduled

            // Associate a trigger with the Job

            // Assign the Job to the scheduler

            throw new NotImplementedException();
        }
    }
}

I’ll get into the implementation in more detail, but let’s look at the minimal configuration a sample configuration file for Quartz.Net service to work.

03 – HelloWorldQuartzDotNet configuration file

In the App.Config file copy the below configuration

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="quartz" 
             type="System.Configuration.NameValueSectionHandler, 
             System, Version=1.0.5000.0,Culture=neutral, 
             PublicKeyToken=b77a5c561934e089" />
  </configSections>
  <quartz>
    <add key="quartz.scheduler.instanceName" value="ServerScheduler" />
    <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
    <add key="quartz.threadPool.threadCount" value="10" />
    <add key="quartz.threadPool.threadPriority" value="2" />
    <add key="quartz.jobStore.misfireThreshold" value="60000" />
    <add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz" />
  </quartz>
</configuration>

As you can see in the configuration above, I have included the instance name of the quartz scheduler, the thread pool type, count and priority, the job store type has been defined as RAM. You have the option of configuring that to ADO.NET JOB store. More details here.

04 – Writing & scheduling a hello world job with Quartz.Net Windows Service

Once fully implemented the ScheduleJob.cs class should look like below. I’ll walk you through the details of the implementation…

– GetScheduler() uses the name of the quartz.net and listens on localhost port 555 to try and connect to the quartz .net windows service.

– Run() an attempt is made to start the scheduler in case it is in standby mode

– I have defined a job “WriteHelloToLog” (that’s the name of the job), this job belongs to the group “IT”. Think of group as a logical grouping feature. It helps you bucket jobs into groups. Quartz.Net gives you the ability to pause or delete all jobs in a group (We’ll look at that in some of the future posts). I have requested for recovery of this job in case the quartz.net service fails over to the other node in the cluster. The jobType is “HelloWorldJob”. This is the class that would be called to execute the job. More details on this below…

– schd.CheckExists will check to ensure that the job WriteHelloToLog doesn’t already exist. If it does, I’ll delete the job and allow you to recreate the same job. I have added this code just as a precaution to avoid you running into the exception “Quartz.ObjectAlreadyExistsException: Unable to store Job with name: ‘WriteHelloWorldToLog’ and group: ‘IT’, because one already exists with this identification.”

– I have defined a trigger for my job. I have called the trigger “WriteHelloToLog”. The Trigger works on the cron schedule “0 0/1 * 1/1 * ? *” which means fire the job once every minute. I would recommend that you look at www.cronmaker.com a free and great website to build and parse cron expressions. The trigger has a priority 1. So, if two jobs are run at the same time, this trigger will have high priority and will be run first.

– Use the Job and Trigger to schedule the job. This method returns a datetime offeset. It is possible to see the next fire time for the job from this variable.

using System.Collections.Specialized;
using Quartz;
using System;
using Quartz.Impl;

namespace HelloWorldQuartzDotNet {
class ScheduledJob : IScheduledJob {
 public
  void Run() {
    // Get an instance of the Quartz.Net scheduler
    var schd = GetScheduler();

    // Start the scheduler if its in standby
    if (!schd.IsStarted) schd.Start();

    // Define the Job to be scheduled
    var job = JobBuilder.Create<HelloWorldJob>()
                  .WithIdentity("WriteHelloToLog", "IT")
                  .RequestRecovery()
                  .Build();

    // Associate a trigger with the Job
    var trigger =
        (ICronTrigger)TriggerBuilder.Create()
            .WithIdentity("WriteHelloToLog", "IT")
            .WithCronSchedule(
                "0 0/1 * 1/1 * ? *")  // visit http://www.cronmaker.com/ Queues
                                      // the job every minute
            .StartAt(DateTime.UtcNow)
            .WithPriority(1)
            .Build();

    // Validate that the job doesn't already exists
    if (schd.CheckExists(new JobKey("WriteHelloToLog", "IT"))) {
      schd.DeleteJob(new JobKey("WriteHelloToLog", "IT"));
    }

    var schedule = schd.ScheduleJob(job, trigger);
    Console.WriteLine("Job '{0}' scheduled for '{1}'", "WriteHelloToLog",
                      schedule.ToString("r"));
  }

  // Get an instance of the Quartz.Net scheduler
 private
  static IScheduler GetScheduler() {
    try {
      var properties = new NameValueCollection();
      properties["quartz.scheduler.instanceName"] = "ServerScheduler";

      // set remoting expoter
      properties["quartz.scheduler.proxy"] = "true";
      properties["quartz.scheduler.proxy.address"] = string.Format(
          "tcp://{0}:{1}/{2}", "localhost", "555", "QuartzScheduler");

      // Get a reference to the scheduler
      var sf = new StdSchedulerFactory(properties);

      return sf.GetScheduler();

    } catch (Exception ex) {
      Console.WriteLine("Scheduler not available: '{0}'", ex.Message);
      throw;
    }
  }
}
} 

The above highlighted values have been taken from the Quartz.config file, this file is available in the Quartz.net server installation directory.

Implementation of my HelloWorldJob Class below.

The HelloWorldJob class gets called to execute the job “WriteHelloToLog” using the once every minute trigger set up for this job. The HelloWorldJob is a class that implements the interface IJob. I’ll walk you through the details of the implementation…

– If you don’t include an empty constructor in the HelloWorldJob class then Quartz.Net windows service will not be able to create an instance of this class to execute your job. I learned this the hard way #JustSaying 

In love

– context is passed to the method execute by the quartz.net scheduler service. This has everything you need to pull out the job, trigger specific information. For example. I have pulled out the value of the jobKey name, the fire time and next fire time.

using Common.Logging;
using Quartz;
using System;

namespace HelloWorldQuartzDotNet {
class HelloWorldJob : IJob {
 private
  static readonly ILog Log = LogManager.GetLogger(typeof(HelloWorldJob));

  /// <summary>
  /// Empty constructor for job initilization
  /// <para>
  /// Quartz requires a public empty constructor so that the
  /// scheduler can instantiate the class whenever it needs.
  /// </para>
  /// </summary>
 public
  HelloWorldJob() {}

 public
  void Execute(IJobExecutionContext context) {
    try {
      Log.DebugFormat(
          "{0}****{0}Job {1} fired @ {2} next scheduled for {3}{0}***{0}",
          Environment.NewLine, context.JobDetail.Key,
          context.FireTimeUtc.Value.ToString("r"),
          context.NextFireTimeUtc.Value.ToString("r"));

      Log.DebugFormat("{0}***{0}Hello World!{0}***{0}", Environment.NewLine);
    } catch (Exception ex) {
      Log.DebugFormat("{0}***{0}Failed: {1}{0}***{0}", Environment.NewLine,
                      ex.Message);
    }
  }
}
}

I’ll add a call to call the scheduler in the Main method in Program.cs

using System;
using System.Threading;

namespace HelloWorldQuartzDotNet {
class Program {
  static void Main(string[] args) {
    try {
      // Infinite loop, so that the console doesn't close on you
      while (true) {
        var sj = new ScheduledJob();
        sj.Run();

        Console.WriteLine(
            @"{0}Check Quartz.net\Trace\application.log.txt for Job updates{0}",
            Environment.NewLine);

        Console.WriteLine(
            "{0}Press Ctrl^C to close the window. The job will continue " +
                "to run via Quartz.Net windows service, " +
                "see job activity in the Quartz.Net Trace file...{0}",
            Environment.NewLine);

        Thread.Sleep(10000 * 100000);
      }
    } catch (Exception ex) {
      Console.WriteLine("Failed: {0}", ex.Message);
      Console.ReadKey();
    }
  }
}
} 

I am going to hit F5 to fire up “HelloWorldQuartzDotNet” project… Let’s see the Quartz.Net job scheduling in action…

SNAGHTML206c76d

Figure – The program has run as expected. The program has successfully scheduled the “WriteHelloWorldToLog” job to the Quartz.Net Scheduler. As you can see the job has been scheduled to start at ‘Sat, 17 Nov 2012 13:19:00 GMT’

Let’s open up the C:\Program Files (x86)\Quartz.Net\Trace\Application.log.txt file to see Quartz.Net scheduler activity…

Note – If you can’t see the log file, then you don’t have logging for Quartz.Net enabled, follow the instructions here

SNAGHTML20d5a1b

Figure – The Quartz. Net application log file has the execution details of my “WriteHelloWorldToLog” job.

05 – Download Quartz.Net sample project and instructions

I have packaged the sample that I created for this blogpost and uploaded it to my skydrive. You can download the sample quartz.net helloworld solution from here.

Once you have downloaded and unpackaged the solution follow the steps below to get it to work,

1. Build the solution and resolve any compilation errors. You might run into compilation issues if you don’t have .net 4 installed on your machine. Ensure that Quartz.dll, Common.Logging.dll, Common.Logging.log4Net.dll and log4Net.dll are correctly available under references.

2. Once successfully compiled, go to the bin folder, copy “HelloWorldQuartzDotNet.exe” and paste it to the Quartz.Net windows service directory. In the example above, the Quartz.Net windows service directory is “C:\Program Files (x86)\Quartz.Net”

3. Stop the Quartz.Net service from Services.msc and start the service again.

4. Hit F5 on the “HelloWorldQuartzDotNet” project in Visual Studio.

And… that’s it…

This was third in the series of posts on enterprise scheduling using Quartz.net, in the next post I’ll be covering how to configure logging for the Quartz.net windows serviceAll Quartz.Net specific blog posts can listed here. Thank you for taking the time out and reading this blog post. If you enjoyed the post, remember to subscribe to http://feeds.feedburner.com/TarunArora. Stay tuned!

This article is part of the GWB Archives. Original Author:  Tarun Arora

Related Posts