Creating a Quartz.Net JobListener
This post will describe how to create a Quartz.Net job listener. As an example, we will write a job history listener that will log job start and end times to a database.
For the task at hand, we will not implement JobExecutionVetoed, since we just want to be notified when a job starts and when it ends. Since we want to log start and end times for our jobs, we will focus on implementing the JobToBeExecuted and the JobWasExecuted methods.
In this method, we will write a record to the database, indicating that the job has started processing. Your implementation of the method could look something like this:
Basically we are inserting a row into a table with all the information we need in order to be able to determine the job’s run time. One thing you should note is that we are creating a GUID and sticking it into the context. This is so that we can record when the job finishes running.
This method gets called whenever the job finishes running. The only thing left to do now is to update the row we inserted when the job began running and set the end time. Here is what that method might look like:
As you can see here, we are reaching into the context and extracting the GUID that we put there when the job started running. This will allow us to update the correct row and thus be able to calculate how long it took the job to finish running.
Now that you have written a job listener. You have a couple of choices:
I hope this post was useful.
Creating the Job Listener
To create a job listener, we need to implement the IJobListener interface. Here is the interface:public interface IJobListener{string Name { get; }void JobExecutionVetoed(JobExecutionContext context);
void JobToBeExecuted(JobExecutionContext context);
void JobWasExecuted(JobExecutionContext context, JobExecutionException jobException);
}
For the task at hand, we will not implement JobExecutionVetoed, since we just want to be notified when a job starts and when it ends. Since we want to log start and end times for our jobs, we will focus on implementing the JobToBeExecuted and the JobWasExecuted methods.
Implementing the JobToBeExecuted Method
In this method, we will write a record to the database, indicating that the job has started processing. Your implementation of the method could look something like this:
Guid historyId = Guid.NewGuid();context.JobDetail.JobDataMap.Add("historyID", historyId);
string sql = @"INSERT INTO [dbo].[QRTZ_JOB_HISTORY]([JobHistoryID],[JobName],[StartDate],[Server],[JobType]) VALUES(@JobHistoryID,@JobName,@StartDate,@Server,@JobType)";using (SqlConnection connection = new SqlConnection(connectionStringGoesHere){connection.Open();using (SqlCommand command = new SqlCommand(sql, connection)){command.Parameters.AddWithValue("@JobHistoryID", historyId);
command.Parameters.AddWithValue("@JobName", context.JobDetail.Name);
command.Parameters.AddWithValue("@StartDate", DateTime.Now);
command.Parameters.AddWithValue("@Server", Environment.MachineName);
command.Parameters.AddWithValue("@JobType", context.JobDetail.JobType.ToString());
command.ExecuteNonQuery();}}
Basically we are inserting a row into a table with all the information we need in order to be able to determine the job’s run time. One thing you should note is that we are creating a GUID and sticking it into the context. This is so that we can record when the job finishes running.
Implementing the JobWasExecuted Method
This method gets called whenever the job finishes running. The only thing left to do now is to update the row we inserted when the job began running and set the end time. Here is what that method might look like:
string sql = "UPDATE [dbo].[QRTZ_JOB_HISTORY] SET [EndDate]=@EndDate WHERE [JobHistoryID]=@JobHistoryID";using (SqlConnection connection = new SqlConnection(connectionStringGoesHere)){connection.Open();using (SqlCommand command = new SqlCommand(sql, connection)){command.Parameters.AddWithValue("@JobHistoryID", (Guid)jobDetail.JobDataMap.Get("historyID"));command.Parameters.AddWithValue("@EndDate", DateTime.Now);
command.ExecuteNonQuery();}}
As you can see here, we are reaching into the context and extracting the GUID that we put there when the job started running. This will allow us to update the correct row and thus be able to calculate how long it took the job to finish running.
Wrapping Up
Now that you have written a job listener. You have a couple of choices:
- You can add the listener directly to your job, in which case only jobs that have the listener attached will log their execution in our database.
- Add the listener as a global listener. Global listeners get called whenever any job runs, and our history listener seems like a good candidate for becoming a global listener. My previous post describes how to schedule a global listener.
I hope this post was useful.