Showing items from Quartz.net

Quartz.Net eBook

For a few months now I have been working on a Quartz.Net eBook. So far I have managed to write a total of 40 pages, out of which about 15 make up the Getting Started section. This section is almost complete. I am reviewing it and will make it available for free on this blog as soon as it has been cleaned up.

Continue Reading

Running Quartz.Net 1.0.2 on .Net 4.0

We recently upgraded one of our application to .Net 4.0. As part of this upgrade, we also upgraded out Quartz.net jobs to run on the 4.0 version of the .Net framework. The process was fairly straightforward, but not without surprises, so I figured I would post it here in case it’s useful. I hope that there will be an official 4.0 release made soon, so I have only included the steps of the process I followed in this post. If there’s enough interest I can upload the updates solution file. If you want to try it out for yourself, I’ve broken the process down into simple steps. Feel free to skip over the steps that are familiar to you.

Step 1 – Downloading the Source Code

First, I downloaded the source code from sourceforge using subversion. The subversion url for the project is: https://quartznet.svn.sourceforge.net/svnroot/quartznet. If you’re using TortoiseSVN, then you just have to right click on the folder you want to download the source to, and then select SVN Checkout. Paste the URL above into the box and select OK. Here’s a screenshot of what I’m talking about:
image

Step 2 – Convert the Solution File

Next locate the main solution file for the maintenance release (this is the branch I used, since it corresponds to the latest released version). The file is called Quartz.2008.sln and is located under branches –> Quartz-1.0-Maintenance. Open this file in VS2010 (right click, select open with… VS2010) and run through the upgrade wizard. Once that’s done, there are some small changes to be made.

Step 3. – Target .Net 4.0

This is the tedious part… you’ll have to right click on each project, select properties and then under the Applications tab, select the new target framework:
image

Step 4 – Fix the Build

If you build the solution now, you’ll get some warnings are errors. You have 2 options:
1. Fix the errors, which are basically documentation errors. You’ll have to look at each of the individual errors to fix them, so I won’t describe the process in detail. Just keep pressing F8 until you’ve fixed them all.
2. Turn off warnings as errors. This is the path of least resistance.
At this point, whether you selected option 1 or 2, you should have a working build. By default, the results of the build are put under the build\2.0 folder:
image

Step 5 – Fix the Version Number and Service Name

Note: this part is optional…
Since I already have a working scheduler and didn’t want to risk screwing it up, I changed the name of the scheduler in the installer file so that I could install it side by side with my existing scheduler to be able to test it. I also changed the version numbers in case for some reason the dlls got mixed up. To change the service name, open Configuration.cs file. It’s under the Quartz.Server.Core project. Change these lines as follows (or use your imagination):
private const string DefaultServiceName = "QuartzServerForNet4";
private const string DefaultServiceDisplayName = "Quartz Server For Net4";
private const string DefaultServiceDescription = "Quartz Job Scheduling Server For Net4";


This will let you install the updated scheduler side by side with the old scheduler.


To update the version number you will have to right click on each project, select properties and then under the application tab, click on the Assembly Information button to update it:


image


Then just, update it to the version number of your preference. Something like this:


image


Step 6 – Final Steps



You should be ready to use Quartz.Net with the 4.0 framework now. If you’re going to install Quartz.net as a service, then take a look at this post. The steps you need to follow will be identical, just remember to use the new files you just built. If you are running Quartz.net embedded in your application, then update your references so they point to the new dlls.

Continue Reading

Creating a Custom Job in Quartz.Net

If you use Quartz.Net and you want to do anything other than run  a batch file, then chances are you’ll want to create a custom job. Fortunately, creating it is not hard at all. Let’s get started.
Here’s a quick rundown of what you need to do. First, you’ll need to add a reference to Quartz.dll in your project, Second, create a class that implements IJob. Third, put the code you want to run inside the Execute method. That’s it! That’s all you really need to create a custom job.
However, in order to get this job to execute, there are a couple more steps to follow and a few more things to be aware of, including some not-so-evident gotchas.
I’m going to assume that at this point, you have created your MyJob class and that it implements the IJob interface. Let’s talk  about what you need to do in addition to implementing the logic that you want your job to execute.

Handle Exceptions
You should wrap the code in the Execute method and handle any exceptions that you can. For exceptions that you cannot handle but that can be solved by running the job again, you should wrap your exception inside a JobExecutionException.
If you want the scheduler to try running the job again, then set the RefireImmediately property to true. Otherwise, set it to false. You also have other options, such as un-scheduling triggers, so take a look at the documentation for JobExecutionException.
If your job doesn’t know how to handle the exception that was thrown, then don’t catch it and let the scheduler handle it.
Deploy Your Custom Job
Deploying the custom job is as simple as copying the dll to the same folder where the Quartz.dll is. You can also deploy your dll in any manner that allows the runtime to locate the dll per the normal rules for dll resolution.
Beware of ConfigurationManager
Finally, I’d like to give you a heads up about using the ConfigurationManager to provide your job with configuration information. Don’t do it! It is best to include all the information that your job needs to execute in the job’s JobDataMap. The reason for this is simple. If you use ConfigurationManager and you are running Quartz.Net as a windows service, then the ConfigurationManager will try to look for configuration information in the Quartz.Net config file. If you are running Quartz.Net embedded inside your application, then this might not be an issue for you, but then again… it might.
Let’s wrap up this post by summarizing the steps needed to create a custom Quartz.Net job.
  1. Add a reference to Quartz.dll in your project.
  2. Create a class that implements IJob
  3. Implement the Execute method of the IJob interface.
  4. Catch exceptions and throw a JobExecutionException as needed.
  5. Copy the CustomJob dll to the same folder as Quartz.dll or somewhere that the runtime can locate it.
If you need more information, please let me know in the comments or read over documentation for IJob and for JobExcecutionException.

Continue Reading

Configuring Quartz.Net to use Log4net

If you’re considering using Quartz.Net, chances are you are using log4net as the logging framework for your application. We’ll assume that you already know how to configure log4net and that you just want to plug that configuration into Quartz.Net. So, how do we configure Quartz.Net to use log4net?
It’s not terribly complicated, since Quartz.Net is using Common.Logging. In this post we’ll consider 2 use cases for configuring Quartz.Net to use log4net: a standalone Quartz.Net server, and Quartz.Net embedded within your application. Fortunately for us, the process we need to follow to configure Quartz.Net is the same for both!

Configuring Quartz.Net with Log4net
To configure log4net for a standalone Quartz.Net server running as a windows service, we have to make some changes to the Quartz.Server.Service.exe.config file. This file should be in the directory where you have your Quartz.Net installation. If Quartz.Net is embedded in your application, then you will be modifying your application’s config file (web.config or yourapp.exe.config for example).
You will need to add 2 elements to the <configSections> element:
<section
name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

This bit lets you configure log4net directly from the quart configuration file. Now, add these elements:
<sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>

This lets you configure the Commons Logging from the quartz configuration file as well. All in all, your <configSections> section will look something like this:
<configSections>
  <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  <sectionGroup name="common">
    <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
  </sectionGroup>
</configSections>

So far all we have done is set up the configuration file to be able to configure both commons logging and log4net from within that one file. Now, let’s configure commons logging to use log4net. Just add this somewhere under the <configuration> element:
<common>
    <logging>
      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
        <arg key="configType" value="INLINE" />
      </factoryAdapter>
    </logging>
  </common>

This tells commons logging that we are going to log to log4net. Now, all that is left to do is to configure log4net itself. Here is a sample log4net configuration:
<log4net>
   <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
     <layout type="log4net.Layout.PatternLayout">
       <conversionPattern value="%d [%t] %-5p %l - %m%n" />
     </layout>
   </appender>
   <root>
     <level value="INFO" />
     <appender-ref ref="EventLogAppender" />
   </root>
</log4net>

To wrap up this post, let me point out 2 things to keep in mind when configuring log4net with Quartz.net:
  1. You don’t need to configure log4net in the main application config file. You can load an external log4net configuration file, just as you would if you weren’t using Quartz.Net.
  2. You do need to tell commons logging to use log4net as the logging framework, which is what we did in the <common> section.
You can also read more on configuring commons logging to use log4net from the Common.Logging documentation.

Continue Reading

Getting Started With Quartz.Net Part 5 – Configuring Triggers

In Part 4, we explained how to configure jobs in detail. In this final installment of the series we’ll describe how to configure two kinds of triggers: the CronTrigger and the SimpleTrigger.
In keeping with the previous posts, we will configure the triggers in the quartz_jobs.xml file. Part 4 included a sample configuration of a CronTrigger, so let’s start with this. Here is the xml fragment that we are going to work with:
<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 * * * * ?</cron-expression>
    </cron>
  </trigger>

Common Properties
The first 3 elements should be familiar to you. They are used to describe and identify the trigger. The trigger is identified by both the name and the group.  You can have triggers with the same name as long as they are not in the same group.
The next element on the list is the misfire-instruction. This element tells the scheduler what it should do if the trigger misfires. A trigger misfires when the scheduler is unable to fire the trigger when it was supposed to be fired. This could be because the scheduler was down or too busy, for example. The two built-in types of misfire instructions are InstructionNotSet, which is the default setting if no misfire instruction is specified and SmartPolicy.  The SmartPolicy instruction is a high level instruction that basically asks each trigger to decide what the “smart” thing to do is.
The Cron trigger provides (in addition to the instructions listed above)  the following MisfireInstruction values: FireOnceNow and DoNothing. For a Cron trigger the SmartPolicy instruction translates to FireOnceNow. The names are pretty descriptive as far as what the scheduler should do.
The SimpleTrigger also provides some additional MisfireInstructions: FireNow, RescheduleNowWithExistingRepeatCount, RescheduleNowWithRemainingRepeatCount,RescheduleNextWithRemainingCount and RescheduleNextWithExistingCount. If you select a SmartPolicy MisfireInstruction for the SimpleTrigger, things aren’t that simple anymore. The documentation explains what will happen as follows:
If the Repeat Count is 0, then the instruction will be interpreted as FireNow. If the Repeat Count is RepeatIndefinitely, then the instruction will be interpreted as RescheduleNowWithRemainingRepeatCount. There is also the following warning: using RescheduleNowWithRemainingRepeatCount with a trigger that has a non-null end-time may cause the trigger to never fire again if the end-time arrived during the misfire time span. Finally, if the Repeat Count is > 0, then the instruction will be interpreted as RescheduleNowWithExistingRepeatCount.
As you can see, it’s really not that simple… However, that covers the MisfireInstruction part. Now it’s time to look at the Volatile property, which so happens to be the same as for the Job and that we discussed in Part 4:
The description of the volatile parameter has a double negative in the documentation description, so I’ll try to rephrase it in a way that is a bit less confusing. If you set the volatile parameter to true, the job will not be persisted in the job store when the scheduler is shut down. If you set the volatile parameter to false, the job will get persisted in the job store. Note, however, that if you are using the AdoJobStore, the job will get persisted regardless of the value of this parameter. Also consider the fact that if you are using the in memory data store… no data will get persisted and you will have to re-schedule all the jobs upon start up.
Next up are the JobName and JobGroup properties, which effectively link the trigger to the job. A trigger can only be assigned to one job and the job’s name and group are needed in order to uniquely identify the job. Make sure these match the name and group of the job you want to schedule.
You can also set the trigger’s start and end times, by adding these elements:
<start-time></start-time>
<end-time></end-time>

Make sure you specify the times in UTC!
Cron Trigger Properties
The last property that we need to provide for a Cron trigger is the Cron expression. This expression follows “mostly” the standard cron syntax, but there are some differences that can cause some frustration, so be sure to look at the documentation. The Quartz.Net cron expression documentation is here and the link also has some examples of the most common expressions.
Simple Trigger Properties
Here is an xml fragment for configuring the simple trigger. We’ll only discuss the last two elements, because the rest of them work just as we described above.
<trigger>
  <simple>
    <name>sampleSimpleTrigger</name>
    <group>sampleSimpleGroup</group>
    <description>Simple trigger to simply fire sample job</description>
    <misfire-instruction>SmartPolicy</misfire-instruction>
    <volatile>false</volatile>
    <job-name>sampleJob</job-name>
    <job-group>sampleGroup</job-group>
    <repeat-count>RepeatIndefinitely</repeat-count>
    <repeat-interval>3000</repeat-interval>
  </simple>
</trigger>

The RepeatCount is used to tell the trigger how many times to fire. You can either specify a number or you can specify RepeatIndefinitely, which basically means the trigger keeps firing over and over again.
The RepeatInterval property sets the time interval at which to repeat the trigger. The example is set in milliseconds.
With this last post I think we have covered pretty much everything that you need to know to set up, configure and run a Quartz.Net server.
Thanks for reading!

Continue Reading