Getting Started With Quartz.Net: Part 3

In Part 2 of this series you learned how to configure the Quartz.Net service, and now it’s time to get your server to actually do something. Let’s look at how to load some jobs via the quartz_jobs.xml file.
First, consider this short description of how the overall process works:

  • When you start the server, a job store is created in memory.
  • This job store is empty until we load some jobs in it.
  • As part of the server startup, the xml plug-in runs, and it reads the quartz_jobs.xml.
  • The plug-in then creates the jobs and triggers that are described in this file.
If you have set up your Quartz.net job server as we described in the previous posts, then all you need to do to load some jobs is to add them to quartz_jobs.xml file. The file that comes with the distribution sets up a NoOpJob, which as its name implies, does nothing. Let’s look at the very first line (ok, the second):
overwrite-existing-jobs="true"
This line tells the xml plug-in to delete any existing jobs that match the jobs that we have in the xml file. So, what makes a job unique in Quartz.Net? The job’s name AND the job’s group. You can create jobs with different names in the same group or jobs with the same name in different groups. If you try to create 2 jobs with the same name and in the same group, you’ll get an error. In this case however, it really doesn’t matter because the job store that we are using (where the job and trigger information is stored) is a RAM job store, therefore once the server is stopped, all this information disappears.
Now it’s time to configure our own job. We’ll configure a NativeJob, which is basically anything that can be run from the command line. In order to get a job to run, we need to configure 2 items: a job, and a trigger. The job is what actually does the work and the trigger is responsible for starting the job.
This xml fragment demonstrates how to configure a NativeJob and cron trigger that fires the 2nd and the 15th of every month at 4:00 am. Ok, that’s not very helpful for testing, so change the cron expression to 0 * * * * ? so that the job runs every minute. Also, if you end up setting your company’s payroll to run every minute, please let me know where I can apply for a job there :-).
<job>
<job-detail>
<name>PayrollProcessor</name>
<group>Payroll</group>
<description>Process paychecks</description>
<job-type>Quartz.Job.NativeJob, Quartz</job-type>
<volatile>false</volatile>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>command</key>
<value>"payroll.bat"</value>
</entry>
<entry>
<key>parameters</key>
<value>"IncreaseSalary"</value>
</entry>
<entry>
<key>waitForProcess</key>
<value>true</value>
</entry>
<entry>
<key>consumeStreams</key>
<value>true</value>
</entry>
</job-data-map>
</job-detail>
<trigger>
<cron>
<name>PayrollProcessorTrigger</name>
<group>Payroll</group>
<description>Trigger payroll</description>
<misfire-instruction>SmartPolicy</misfire-instruction>
<volatile>false</volatile>
<job-name>PayrollProcessor</job-name>
<job-group>Payroll</job-group>
<cron-expression>0 0 4 2,15 1-12 ?</cron-expression>
</cron>
</trigger>
</job>

If you change the command from payroll.bat to the name of your executable (make sure you include the full path!), you should be able to get Quartz.Net to run your own job. I would recommend keeping the quotes there, because if your command has spaces in it and you don’t wrap the command in quotes, Quartz.Net won’t be able to run it.
Now that you’ve configured the job, let’s give it a try. Save the quart_jobs.xml file, start the Quartz.Net service and take a look at the event log. You should see some entries similar to these if everything was set up properly:
Quartz.Xml.JobSchedulingDataProcessor.ProcessFile(:0) - Parsing XML file: C:\quartz\quartz_jobs.xml with systemId: C:\quartz\quartz_jobs.xml validating: False validating schema: True
Quartz.Xml.JobSchedulingDataProcessor.ScheduleJobs(:0) - Scheduling 1 parsed jobs.
Quartz.Xml.JobSchedulingDataProcessor.ScheduleJob(:0) - Adding job: Payroll.PayrollProcessor
Quartz.Xml.JobSchedulingDataProcessor.ScheduleJobs(:0) - 1 scheduled jobs.
Quartz.Job.NativeJob.RunNativeCommand(:0) - About to run cmd.exe /C "C:\quartz\payroll.bat" IncreaseSalary

So there you have it, the scheduler is running the payroll.bat batch file and passing in the IncreaseSalary parameter. Plug in your own batch or program file and parameters and see what happens.
A word of caution: running command line jobs can get tricky because of spaces and parameter formats, so try running your program with the parameters from a command line first to see what happens. Sometimes it takes a little trial and error to get it to work just right. For this reason, you will usually want to create your own job (more on this later, or look at the Quartz.Net tutorial. A custom job gives you more control over what happens when and what to do in case of an emergency.
Because this is already a long post, I’ll defer until my next post the details of each of the job and trigger settings, but if you’re curious or in desperate and immediate need to know more, read through the following documentation links, which should answer most of your questions:
General Job (IJob) documentation
NativeJob documentation
General Trigger documentation
Cron trigger documentation

Continue Reading

Getting Started With Quartz.Net: Part 1

In this series of posts I will try to help you get started using Quartz.Net, the C# port of Quartz. This tutorial assumes that you are using the latest version of the .Net framework, so if you are using a different version, make sure you adapt the instructions accordingly. Also, I assume that you are somewhat familiar with installing and managing windows services.
This first installment will walk you through installing Quartz.Net as a standalone windows service.
1. Download the latest version (which at this time is 1.o) zip file from http://quartznet.sourceforge.net/download.html. Unzip the file to any temporary folder (I’m using C:\Temp\Quartz for the example). We will not be keeping this folder (unless you want to).
2. Locate the C:\temp\Quartz\server\bin\3.5\service folder. It contains all the files that you need to install the service.
quartzfiles
3. Copy all the files in this folder to the folder that will serve as your Quartz server installation folder. I will use C:\Quartz as my installation folder.
4. Once you have copied all the files there, it is time to install the service. We will use installutil.exe to do this. The easiest way to run the installer is to open a Visual Studio Command Prompt and navigate to C:\Quartz (or your install folder). If you’re running Vista or Windows 7, you’ll need to run the command prompt as Administrator (thanks sashas and max). Then run the following command to install the service:
installutil Quartz.Server.Service.exe
installPrompt
5. If the install ran successfully, you will have a screen that looks like this:
installSuccess
At this point the service should be installed. Open the services manager and change the account and startup type if necessary.
Part 2 of this series will discuss how to configure and start the Quartz.net server.

Continue Reading

Getting Started With Quartz.Net: Part 2

This is the second instalment of the Getting Started With Quartz.Net series. Part 1 covered how to set up a standalone Quart.Net server as a windows service. Part 2 covers the configuration of the server.
At this point you should have installed the Quartz.Net server as a standalone windows service. If you haven’t, Part 1 guides you through this process.
Now, let’s look at configuring the server. There are 3 files we need to look at: Quartz.Server.Service.exe.config, quartz.config and quartz_jobs.xml.
Quartz.Server.Service.exe.configFirst we will examine Quartz.Server.Service.exe.config, so open this file in your favorite editor. The distribution version of the file does minimal configuration here, only setting up the logging sub systems. Of interest here is the <log4net> section, which you can modify if you don’t want your service to log to the event log. If you’re not sure how to configure log4net, visit the log4net site and look at the log4net configuration examples.
quartz.configNext, let’s look at quartz.config, which contains the bulk of the configuration. This file has 3 “sections” that are worth looking at. The first “section” starts on line 7:
# configure thread pool info
quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz
quartz.threadPool.threadCount = 10
quartz.threadPool.threadPriority = Normal

Here you can change the number of threads in the threadpool by changing the threadCount property. This basically translates into how many jobs can run at the same time.
The next section starts on line 12 and initializes the JobInitializationPlugin, which will load up a set of jobs from an xml file when the server is started:
# job initialization plugin handles our xml reading, without it defaults are used -->
quartz.plugin.xml.type = Quartz.Plugin.Xml.JobInitializationPlugin, Quartz
quartz.plugin.xml.fileNames = ~/quartz_jobs.xml

The interesting part here is the last line, where you can tell the plugin which file to load the jobs from.
The final section configures the server so that it can be managed remotely. We won’t look at this section right now since we don’t need to change it to run the server.
quartz_jobs.xml
The last configuration file that we will look at is quartz_jobs.xml, which contains the jobs that will be loaded by the initialization plugin. The file available with the distribution includes a sample job configuration of a job that does absolutely nothing. This is the file where you want to set up your own jobs. You can configure your jobs here and then start up the Quartz.Net service. The plugin will then read this file and schedule the jobs. Part 3 of the series will cover how to configure jobs via the xml file.
To wrap up this post, there are a couple of things that are worth pointing out:
Running the server using these default configuration files will start up a server that:

  • Logs events to the windows event log
  • Uses a memory based job store (more on this later)
  • Loads jobs from an xml file
  • Schedules a NoOpJob that runs every 3 seconds.
  • Can be managed remotely
Part 3 of the series will cover how to configure jobs via the xml file.

Continue Reading