Saturday, June 25, 2011

Implementing a Job Listener in Quartz.Net 2.0

NOTE: I'm now blogging at http://jayvilalta.com/blog and not updating this blog anymore. For information on the latest version of Quartz.Net, visit me there.

In this post we will be implementing the job listener that we discussed in the previous post. The previous post showed us how to add a scheduler listener to the scheduler using a plugin. Now we will describe what you need to do to implement a job listener in Quartz.Net 2.0. If you’re interested in learning how to implement a job listener in version 1.0 of Quartz.Net, take a look at this post.

Implementing the IJobListener Interface

To create a job listener, we must write a class that implements the IJobListener interface. This interface is defined as follows:
public interface IJobListener
 {
    string Name { get; }
    void JobExecutionVetoed(IJobExecutionContext context);
    void JobToBeExecuted(IJobExecutionContext context);
    void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException);
 }


The Name property will hold the name of the job listener and is read-only. The rest of the interface is what is of most interest to us. These three methods give you the opportunity to interact with a job during its lifecycle. The first method, JobExecutionVetoed gets called whenever a trigger listener vetoes the execution of a job. If this method is called, no other methods in this interface will be called. The second method, JobToBeExecuted, is called right before the job is about to be executed. The third method, JobWasExecuted, is called after the job has been executed. You do not have to provide implementations for all 3 methods unless you want to, but the methods do need to be present in your class to satisfy the interface.


The JobListenerExample



In our example we will provide very simple implementations of these methods, only to illustrate how to build a listener. All the JobListenerExample does is log an informational message whenever one of the methods of the interface are called. The code for the simple listener is listed below.


class JobListenerExample : IJobListener
 {
    public void JobExecutionVetoed(IJobExecutionContext context)
    {
        logger.Info("JobExecutionVetoed");
    }
    public void JobToBeExecuted(IJobExecutionContext context)
    {
        logger.Info("JobToBeExecuted");
    }
    public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
    {
        logger.Info("JobWasExecuted");
    }
    public string Name
    {
        get { return "JobListenerExample"; }
    }
    private static readonly ILog logger = LogManager.GetLogger(typeof(JobListenerExample));
 }



If you would like a more in depth example of a job listener that actually does something useful, take look at this post, which describes how to implement a job listener that logs job execution information to a database. The example is for Quartz.Net 1.0, but you’ll notice that the only difference between the two interfaces is that the method signatures are now defined using interfaces instead of concrete types.


Loading and Executing the Listener



In order to load and execute your listener, you will have to add it to the scheduler upon start up. You must also specify whether it should executed for all jobs, or for some job in particular. How to do this using a plugin is described in the previous post. Finally, you must make sure that the assembly that contains your listener is available somewhere that the scheduler can load it upon startup.

6 comments:

Anonymous said...

I was looking at this and your earlier post for the 1.x release and had one question.

If the AdoJobStore is being used, it would be nice to log to the database. Is there any way to connect to the same database that the jobs are contained in?

J said...

I don't think there's a way to get at it from say the scheduler or the context. Some job stores don't have a datasource concept. The way I've done it in the past is to put the connection string either in the configuration file or in each job's data map.

raxmendoza said...

Hi,

I am currently using Quartz 1.x version for a very small monitoring application.

to update the GUI, i am using a global listener which checks the JobExecutionContext during the different events to send a signal to the main thread (by calling a delegate) to update the status of the different jobs. i am trying to execute one of the jobs manually (the trigger is a CRON trigger), and did it using the following:

first: _scheduler.TriggerJob(jobid, groupname);

which doesn't trigger the job

second:
_scheduler.TriggerJobWithVolatileTrigger(jobid, groupname);

triggers the job but contains a null JobExecutionContext object.

As i've said, i'm using the context to send to the delegate which entry in the list to update.

Am I doing somehting wrong? What other approaches do you recommend?

BTW, I'm excited for your 2.0 release - would it still support .NET Framework 2.0 (unfortunately, i can't upgrade due to requirements)

Mika Jacobi said...

Very Useful indeed. Thank you.

J said...

Thanks for the feedback!

Unknown said...

Hi,

Can some one say how to use an a joblistener in quart (Who to use joblistener in an xml file when you have a class Myjoblistener who implement Joblistener)

Please some one help me.
Thanks