Quartz.Net Writing your first Hello World Job
- by Tarun Arora
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 If you are new to Quartz.Net I would recommend going through, A brief introduction to Quartz.net Walkthrough of Installing & Testing Quartz.Net as a Windows Service A few things to consider before you should schedule a Job using Quartz.Net - An instance of the scheduler service - A trigger - And last but not the least a job 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 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). 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.
Quartz.Net configuration
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.
Writing & scheduling a hello world job with Quartz.Net
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 “WriteHelloToConsole” (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…
- I have defined a trigger for my job. I have called the trigger “WriteHelloToConsole”. 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 System.Configuration;
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("WriteHelloToConsole", "IT")
.RequestRecovery()
.Build();
// Associate a trigger with the Job
var trigger = (ICronTrigger)TriggerBuilder.Create()
.WithIdentity("WriteHelloToConsole", "IT")
.WithCronSchedule("0 0/1 * 1/1 * ? *") // visit http://www.cronmaker.com/ Queues the job every minute
.WithPriority(1)
.Build();
// Assign the Job to the scheduler
var schedule = schd.ScheduleJob(job, trigger);
Console.WriteLine("Job '{0}' scheduled for '{1}'", "", 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 “WriteHelloToConsole” 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…
- 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 Quartz;
using System;
namespace HelloWorldQuartzDotNet
{
class HelloWorldJob : IJob
{
public void Execute(IJobExecutionContext context)
{
try
{
Console.WriteLine("Job {0} fired @ {1} next scheduled for {2}", context.JobDetail.Key,
context.FireTimeUtc.Value.ToString("r"), context.NextFireTimeUtc.Value.ToString("r"));
Console.WriteLine("Hello World!");
}
catch (Exception ex)
{
Console.WriteLine("Failed: {0}", 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
{
var sj = new ScheduledJob();
sj.Run();
Thread.Sleep(10000 * 10000);
}
catch (Exception ex)
{
Console.WriteLine("Failed: {0}", ex.Message);
}
}
}
}
This was third in the series of posts on enterprise scheduling using Quartz.net, in the next post I’ll be covering how to pass parameters to the scheduled task scheduled on Quartz.net windows service. 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!