Quartz.Net Trigger Listeners, Part 4 of Quartz.Net Listeners in Detail

This is the fourth post in the Quartz.Net Listener Tutorial series. It’s also the fourth part of the introduction to listeners overview series. You can find Part 1 here, Part 2 here and Part 3 here. Today we’ll be looking at trigger listeners and how to implement one.

As we mentioned in Part 1, trigger listeners get notified of trigger level events. To implement a trigger listener, you need to implement the ITriggerListener interface. Here’s what that interface looks like:

1 public interface ITriggerListener
2 {
3     string Name { get; }
4     void TriggerFired(ITrigger trigger, IJobExecutionContext context);
5     bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context);
6     void TriggerMisfired(ITrigger trigger);
7     void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode);
8 }

You’ll notice that trigger listeners get notified when the trigger is fired (line 4), when the trigger misfires (line 6) and when the trigger is complete (line 7). There is one other method that also gets called on the trigger listener that needs special attention. When the VetoJobExecution (line 5) method is called, the trigger listener can tell the scheduler to ignore the trigger. Essentially it vetoes the firing of the trigger.

Now let's build a trigger listener that implements all of these methods. Download the sample code from the Quartz.Net ebook if you want to follow along. Here's the code for the trigger listener we'll be going over:

 1 using Quartz;
 2 using System;
 3 using System.Reflection;
 4 
 5 namespace Examples
 6 {
 7     class TriggerListenerExample:ITriggerListener
 8     {
 9         public void TriggerFired(ITrigger trigger, IJobExecutionContext context)
10         {
11             Console.WriteLine("The scheduler called {0} for trigger {1}", MethodBase.GetCurrentMethod().Name, trigger.Key);
12         }
13 
14         public bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context)
15         {
16             Console.WriteLine("The scheduler called {0} for trigger {1}", MethodBase.GetCurrentMethod().Name,trigger.Key);
17             return false;
18         }
19 
20         public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode)
21         {
22             Console.WriteLine("The scheduler called {0} for trigger {1}", MethodBase.GetCurrentMethod().Name, trigger.Key);
23         }
24 
25         public void TriggerMisfired(ITrigger trigger)
26         {
27             Console.WriteLine("The scheduler called {0} for trigger {1}", MethodBase.GetCurrentMethod().Name, trigger.Key);
28         }
29 
30         public string Name
31         {
32             get { return "TriggerListenerExample"; }
33         }
34     }
35 }

This is a very simple listener, as it only logs any calls made to it, but it's quite useful because it provides insight into which methods are called when.

First, take a look at the TriggerFired method (line 9), since it is the very first method that gets called on the trigger listener. After the TriggerFired method gets called, the VetoJobExecution (line 14) gets called. You'll notice that our implementation returns true always. If this method returns false, then the JobExecutionVetoed method will get called on the job listener (if there are any) and the job will not get executed.

Next, let's look at the TriggerComplete method (line 20). This method gets called when trigger has completed, which means that it gets called after the trigger has fired and after the associated job has finished executing.

The TriggerMisfired method (line 25) will get called if the trigger ever misfires, so it's a little out of place, because it's not really related to the job processing lifecycle.

Finally, let's look at the Name property (line 30). Not much excitement here, as it just returns the name of the listener.

Now that we've reviewed the code for the listener, let's take a look at the listener in action. Here's the output generated by running the scheduler with the configured examples.

 1 The scheduler called SchedulerStarting
 2 The scheduler called JobAdded for job directoryScanJobExample.directoryScanJobExample
 3 The scheduler called JobScheduled for job directoryScanJobExample.directoryScanJobExample, caused by trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
 4 The scheduler called JobAdded for job directoryScanJobExample.addDirectoryScanListener
 5 The scheduler called JobScheduled for job directoryScanJobExample.addDirectoryScanListener, caused by trigger directoryScanJobExampleSimpleTriggerGroup.addDirectoryScanListenerSimpleTrigger
 6 The scheduler called JobUnscheduled
 7 The scheduler called JobScheduled for job directoryScanJobExample.directoryScanJobExample, caused by trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
 8 The scheduler called JobUnscheduled
 9 The scheduler called JobScheduled for job directoryScanJobExample.addDirectoryScanListener, caused by trigger directoryScanJobExampleSimpleTriggerGroup.addDirectoryScanListenerSimpleTrigger
10 The scheduler called SchedulerStarted
11 IsStarted=True
12 SchedulerInstanceId=NON_CLUSTERED
13 SchedulerName=ServerScheduler
14 The scheduler is running. Press any key to stop
15 The scheduler called TriggerFired for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
16 The scheduler called TriggerFired for trigger directoryScanJobExampleSimpleTriggerGroup.addDirectoryScanListenerSimpleTrigger
17 The scheduler called VetoJobExecution for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
18 The scheduler called VetoJobExecution for trigger directoryScanJobExampleSimpleTriggerGroup.addDirectoryScanListenerSimpleTrigger
19 The scheduler called JobToBeExecuted for job directoryScanJobExample.directoryScanJobExample
20 The scheduler called JobToBeExecuted for job directoryScanJobExample.addDirectoryScanListener
21 Job addDirectoryScanListener in group directoryScanJobExample is about to be executed
22 Job directoryScanJobExample in group directoryScanJobExample is about to be executed
23 The scheduler called JobWasExecuted for job directoryScanJobExample.addDirectoryScanListener
24 The scheduler called JobWasExecuted for job directoryScanJobExample.directoryScanJobExample
25 Job addDirectoryScanListener in group directoryScanJobExample was executed in 29ms
26 Job directoryScanJobExample in group directoryScanJobExample was executed in 33ms
27 The scheduler called TriggerComplete for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
28 The scheduler called TriggerComplete for trigger directoryScanJobExampleSimpleTriggerGroup.addDirectoryScanListenerSimpleTrigger
29 The scheduler called TriggerFinalized for trigger directoryScanJobExampleSimpleTriggerGroup.addDirectoryScanListenerSimpleTrigger, belonging to job directoryScanJobExample.addDirectoryScanListener
30 The scheduler called JobDeleted for job directoryScanJobExample.addDirectoryScanListener
31 The scheduler called TriggerFired for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
32 The scheduler called VetoJobExecution for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
33 The scheduler called JobToBeExecuted for job directoryScanJobExample.directoryScanJobExample
34 Job directoryScanJobExample in group directoryScanJobExample is about to be executed
35 The scheduler called JobWasExecuted for job directoryScanJobExample.directoryScanJobExample
36 Job directoryScanJobExample in group directoryScanJobExample was executed in 5ms
37 The scheduler called TriggerComplete for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
38 The scheduler called TriggerFired for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
39 The scheduler called VetoJobExecution for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
40 The scheduler called JobToBeExecuted for job directoryScanJobExample.directoryScanJobExample
41 Job directoryScanJobExample in group directoryScanJobExample is about to be executed
42 The scheduler called JobWasExecuted for job directoryScanJobExample.directoryScanJobExample
43 Job directoryScanJobExample in group directoryScanJobExample was executed in 5ms
44 The scheduler called TriggerComplete for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger
45 The scheduler called TriggerFinalized for trigger directoryScanJobExampleSimpleTriggerGroup.directoryScanJobExampleSimpleTrigger, belonging to job directoryScanJobExample.directoryScanJobExample
46 The scheduler called JobDeleted for job directoryScanJobExample.directoryScanJobExample
47  Shutting down scheduler
48 The scheduler called SchedulerInStandbyMode
49 The scheduler called SchedulerShuttingdown
50 The scheduler called SchedulerShutdown
51 IsShutdown=True
52 The scheduler has been shutdown.

This listing includes all of the output from the listeners we've covered so far, so it gives us an example of how it all comes together. The first few lines (1-14) are output by the scheduler listener as the scheduler gets started and the jobs get scheduled. Once the scheduler has started, we can see that there are 2 TriggerFired method calls (lines 15 and 16). One runs the directory scan job and the other one basically "installs" the directory scan listener. Next, the scheduler calls the VetoJobExecution method on both trigger listeners (lines 17 and 18). You'll notice that we only created one listener but it's getting called for both triggers. That's because our listener was added with a matcher that matches all of the triggers. Take a look at the PluginExample file if you're not sure about what's going on.

Since our trigger listener returns false when the VetoJobExecution method is called, the scheduler then executes the jobs attached to the triggers. After the jobs have finished running, the TriggerComplete method is called for both triggers (lines 27 and 28). This means that the triggers are done for now. One of the triggers is not supposed to run again, so the scheduler calls the TriggerFinalized method on the scheduler listener (line 29). This trigger won't fire again. Because the job that is attached to that trigger is not set to persist, then the scheduler will delete the job from the schedule as well (line 30).

We still have one trigger that needs to keep firing, so you'll notice that the cycle will repeat for this trigger (lines 31 through 44). The TriggerFired method is called, then the VetoJobExecution, then the TriggerComplete method is called. Finally, the trigger's repeat count is zero and then the scheduler will call the TriggerFinalized method on the scheduler listener (not the trigger listener!) and delete the job (lines 45 and 46).

I hope seeing this all in one place makes it come together for you. We'll stop here for now and in our next post we'll go over the Quart.Net built-in listeners.

Moving from Wordpress to Jekyll

If you visit my blog frequently, you may have noticed that the layout of the site has changed drastically. Can you guess why? Yes, I switched from using wordpress to using Jekyll.

Why switch?

Speed

Basically because I wanted my site to load faster. I moved off shared hosting and into Azure to speed up the site and there definitely was an improvement. However, it's pretty hard to beat a static site, so I'm going with static for now.

More content

As Jekyll has a blogger importer, I was able to import my old posts and now they're all available on this site.

Less maintenace

No more backing up MySql and updgrading Wordpress

What I'm Giving Up

Comments

For now I'm giving up on comments but I may add them later. All in all I don't get many comments.

Forms

I'm also giving up on forms right now but may also add them later. I don't need more spam anyway.

Final Thoughts

It took a while to get everything moved over and getting the feel for how things work. I also discovered I had some broken links left over from the previous migration to Azure. Those should all be fixed now, but do let me know if I missed any.

Now I'll get back to writing some more posts.

Quartz.Net Job Listeners, Part 3 of Quartz.net Listeners in detail

This is the third post in the Quartz.Net Listener Tutorial series. It’s also the third part of the introduction to listeners overview series. You can find Part 1 here and Part 2 here. Today we’ll be looking at job listeners and how to implement one.

As we mentioned in Part 1, job listeners get notified of job level events. To implement a job listener, you need to implement the IJobListener interface. Here’s what that interface looks like:

public interface IJobListener
{
    string Name { get; }
    void JobToBeExecuted(IJobExecutionContext context);
    void JobExecutionVetoed(IJobExecutionContext context);
    void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException);
}

 

You’ll notice that job listeners get notified when the job is about to be executed, after it was executed, and if it’s execution was vetoed by a trigger.  Let’s build a job listener that measures how long it took for job to execute.  Download the sample code from the Quartz.Net ebook if you want to follow along.

Here’s the code for the job duration job listener we’ll be going over:

using Quartz;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Examples
{
    public class JobDurationListenerExample : IJobListener
    {
        public void JobExecutionVetoed(IJobExecutionContext context)
        {
            // Do nothing
        }

        public void JobToBeExecuted(IJobExecutionContext context)
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            Console.WriteLine("Job {0} in group {1} is about to be executed", context.JobDetail.Key.Name, context.JobDetail.Key.Group);
            _Stopwatches.Add(context.FireInstanceId, stopwatch);
        }

        public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
        {
            var elapsed = _Stopwatches[context.FireInstanceId].ElapsedMilliseconds;
            Console.WriteLine("Job {0} in group {1} was executed in {2}ms", context.JobDetail.Key.Name, context.JobDetail.Key.Group, elapsed);
        }

        public string Name
        {
            get { return "JobDurationListener"; }
        }
        private Dictionary<string, Stopwatch> _Stopwatches = new Dictionary<string, Stopwatch>();
    }
}

 

First, let’s look at the JobExecutionVetoed method (line 12). We’re not going to do anything there, so I just added a comment. If you wanted to be notified if a trigger ever vetoed a job execution, then add your code here. If you need additional information about which job is running or which trigger fired, it’s all available in the context object. You’ll see how it’s used in a minute.

Second, let’s look at the JobToBeExecuted method (line 17). In this method we’re creating a stopwatch, starting it and adding it to a dictionary so that we can keep track of which job got fired. This job listener listens to all jobs, so we have to keep track of one stopwatch for each job fired. You may want to just listen to events from a given job and you should probably cleanup the stopwatches. Alternatively, you could just store the start time back in the context and then pull it out to compute the duration. Obviously this isn’t production quality code, so use it wisely.

Third, let’s look at the JobWasExecuted method (line 25). Here we pull out the stopwatch and then get the time it took to execute the job.

One last thing… you’ll have to give your listener a name that will be returned by the Name property (line 31).

Now, lets run the samples solution (make sure EmbeddedScheduler is set up as your startup project). You’ll see some output similar to this:

The scheduler called SchedulerStarting
The scheduler called JobAdded
The scheduler called JobScheduled
The scheduler called JobAdded
The scheduler called JobScheduled
The scheduler called JobUnscheduled
The scheduler called JobScheduled
The scheduler called JobUnscheduled
The scheduler called JobScheduled
The scheduler called SchedulerStarted
IsStarted=True
SchedulerInstanceId=NON_CLUSTERED
SchedulerName=ServerScheduler
The scheduler is running. Press any key to stop
The scheduler called JobToBeExecuted
The scheduler called JobToBeExecuted
Job directoryScanJobExample in group directoryScanJobExample is about to be executed
Job addDirectoryScanListener in group directoryScanJobExample is about to be executed
The scheduler called JobWasExecuted
Job addDirectoryScanListener in group directoryScanJobExample was executed in 1ms
The scheduler called JobWasExecuted
Job directoryScanJobExample in group directoryScanJobExample was executed in 1ms
The scheduler called TriggerFinalized
The scheduler called JobDeleted
The scheduler called JobToBeExecuted
Job directoryScanJobExample in group directoryScanJobExample is about to be executed
The scheduler called JobWasExecuted
Job directoryScanJobExample in group directoryScanJobExample was executed in 0ms
The scheduler called JobToBeExecuted
Job directoryScanJobExample in group directoryScanJobExample is about to be executed
The scheduler called JobWasExecuted
Job directoryScanJobExample in group directoryScanJobExample was executed in 0ms

The output shows that we are now logging how long it takes to execute each job (look at lines 20, 22, 28 and 32). The jobs that exist in the scheduler don’t take very long to run,  but you can try it out with a longer running job.

That’s it for job listeners. The next post will cover trigger listeners.

Quartz.Net Scheduler Listeners, Part 2 of Quartz.Net Listeners in Detail

This is the second post in the Quartz.Net Listener Tutorial series. It’s also the second part of the introduction to listeners overview series. You can find Part 1 here. Today we’ll be looking at scheduler listeners and how to implement one.

As we mentioned in Part 1, scheduler listeners get notified of high level scheduler events. To implement a scheduler listener, you need to implement the ISchedulerListener interface. Here’s what that interface looks like:

public interface ISchedulerListener
{
    void JobScheduled(ITrigger trigger);
    void JobUnscheduled(TriggerKey triggerKey);
    void TriggerFinalized(ITrigger trigger);
    void TriggerPaused(TriggerKey triggerKey);
    void TriggersPaused(string triggerGroup);
    void TriggerResumed(TriggerKey triggerKey);
    void TriggersResumed(string triggerGroup);
    void JobAdded(IJobDetail jobDetail);
    void JobDeleted(JobKey jobKey);
    void JobPaused(JobKey jobKey);
    void JobsPaused(string jobGroup);
    void JobResumed(JobKey jobKey);
    void JobsResumed(string jobGroup);
    void SchedulerError(string msg, SchedulerException cause);
    void SchedulerInStandbyMode();
    void SchedulerStarted();
    void SchedulerStarting();
    void SchedulerShutdown();
    void SchedulerShuttingdown();
    void SchedulingDataCleared();
}

 

In a nutshell, those are the scheduler level events that you can get notifications for. Let’s go ahead and make a simple implementation of the scheduler listener. You can download the sample code from the Quartz.Net ebook samples. Open the

QuartzNetBookSamples solution and look for the SchedulerListenerExample.cs file, inside of the Examples project. You’ll see that all we have is a simple implementation that writes a message to the console when one of the events is triggered. The messages are in this format: The scheduler called {methodName}. Here’s what the source code for that looks like:

using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Examples
{
    public class SchedulerListenerExample : ISchedulerListener
    {

        public void JobAdded(IJobDetail jobDetail)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobDeleted(JobKey jobKey)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobPaused(JobKey jobKey)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobResumed(JobKey jobKey)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobScheduled(ITrigger trigger)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobUnscheduled(TriggerKey triggerKey)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobsPaused(string jobGroup)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void JobsResumed(string jobGroup)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulerError(string msg, SchedulerException cause)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulerInStandbyMode()
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulerShutdown()
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulerShuttingdown()
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulerStarted()
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulerStarting()
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void SchedulingDataCleared()
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void TriggerFinalized(ITrigger trigger)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void TriggerPaused(TriggerKey triggerKey)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void TriggerResumed(TriggerKey triggerKey)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void TriggersPaused(string triggerGroup)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }

        public void TriggersResumed(string triggerGroup)
        {
            Console.WriteLine("The scheduler called {0}", MethodBase.GetCurrentMethod().Name);
        }
    }
}

 

 

And if you set the EmbeddedScheduler project as your startup project and press F5, you should see output similar to this:

The scheduler called SchedulerStarting
The scheduler called JobAdded
The scheduler called JobScheduled
The scheduler called JobAdded
The scheduler called JobScheduled
The scheduler called JobUnscheduled
The scheduler called JobScheduled
The scheduler called JobUnscheduled
The scheduler called JobScheduled
The scheduler called SchedulerStarted
IsStarted=True
SchedulerInstanceId=NON_CLUSTERED
SchedulerName=ServerScheduler
The scheduler is running. Press any key to stop
The scheduler called TriggerFinalized
The scheduler called JobDeleted
Shutting down scheduler
The scheduler called SchedulerInStandbyMode
The scheduler called SchedulerShuttingdown
The scheduler called SchedulerShutdown
IsShutdown=True
The scheduler has been shutdown.

 

If you look at the output, you’ll notice that several of the scheduler’s events were raised and so our listener was notified of them. Lines 1-10, 14-16 and 18-20 were all generated in the listener.

I’d like to call out some not-so-obvious events being raised by the scheduler. Notice that you can add and schedule jobs even before the scheduler starts. Also notice that when shutting the scheduler down, the scheduler gets set to standby mode (line 18).

I think that’s it for scheduler listeners. Next, we’ll be looking at implementing a job listener.

Quartz.Net Listeners in Detail – Part 1

This post is the first post of a series called the Quartz.Net Listener Tutorial. Today we’ll be introducing you to listeners in detail. We’ll cover what they are and what they could be used for. Part 1 will only cover listeners in general. Parts 2-4 will cover the details of the specific types of listeners.

What are Quartz.Net listeners?

Quartz.Net listeners are objects that can be notified when certain events happen inside a Quartz.Net scheduler. There are 3 types of listeners:

  • Scheduler listeners
  • Job listeners
  • Trigger listeners

Let’s look at each of these listeners in more detail.

Scheduler Listeners

Scheduler listeners are used when you want to be notified of scheduler level events. What are scheduler level events? There are quite a few, so I’ve grouped them by the object to which they apply. I think the descriptions are quite descriptive but if you need more detailed information for each of these events, check out the book or the subsequent posts.

Job Events

  • A job was added
  • A job was deleted
  • A job was scheduled
  • A job was unscheduled
  • A job was paused
  • A job was resumed
  • Several jobs were paused
  • Several jobs were resumed

Trigger Events

  • A trigger was finalized
  • A trigger was paused
  • A trigger was resumed
  • Several triggers were paused
  • Several triggers were resumed

Scheduler Events

  • The scheduler is starting
  • The scheduler started
  • The scheduler is shutting down
  • The scheduler has shut down
  • The scheduler has moved to standby mode
  • There was a scheduler error
  • The scheduler’s scheduling data has been cleared

Scheduler listeners must implement the ISchedulerListener interface.

When would I use scheduler listeners?

In general, scheduler level events can be quite useful if you need to keep track or audit changes made to the scheduler and the schedule. Being notified of errors is also useful to monitor possible issues with the scheduler itself.

Job Listeners

Job listeners are used when you want to be notified of job level events. Here’s a list of the events that are supported at the job level:

  • A job’s execution was vetoed
  • A job is about to be executed
  • A job was executed

Job listeners must implement the IJobListener interface

When would I use job listeners?

My favorite use for job listeners is to keep track of how long it takes a given job to run and to monitor that run time duration.

Trigger Listeners

Trigger listeners are used when you want to be notified of trigger level events. Triggers will raise the following events:

  • A trigger has fired
  • A trigger has misfired
  • A trigger has completed
  • Should we veto this execution?

You’ll notice that last event is a bit unusual. We’ll cover that one when we get to trigger listeners post. Trigger listeners must implement the ITriggerListener interface.

When would I use Trigger listeners?

If you want to be able to stop a regularly scheduled job from running, you’ll need to use a trigger listener to veto that execution. Tracking misfires is useful as well to make sure your scheduler is healthy and that things are running within reason.

Up Next

I hope this gives you a good overview of how listeners work in Quartz.Net and what you could do with them. In Part 2 we’ll cover scheduler listeners in more detail.