Writing Custom Rock Jobs

Someday you’ll decide you need to run some custom code on a regular, periodic basis. When that happens, you’ll be glad you learned about Rock Jobs.

A Rock Job is a fairly simple thing. Under the covers, Rock Jobs are just an extension of the popular open-source Quartz job scheduling system. A Rock Job is just a class that implements the Quartz IJob interface, and the only method you need to implement is the Execute method -- which is the starting point for your code. Let’s look at a simple example in the RunSQL job:

using System.Web;
using Quartz;
using Rock.Attribute;
using Rock.Data;
using Rock.Model;
using Rock.Web.UI.Controls;

...
[DisplayName( "Run SQL" )]
[Description( "Job to run quick SQL queries on a schedule." )]

[DisallowConcurrentExecution]
public class RunSQL : IJob
{ 
   ...
   public virtual void Execute( IJobExecutionContext context )
   {
       JobDataMap dataMap = context.JobDetail.JobDataMap;

       // run a SQL query to do something
       string query = dataMap.GetString( "SQLQuery" );
       int? commandTimeout = dataMap.GetString( "CommandTimeout").AsIntegerOrNull();
       try
       {
           int rows = DbService.ExecuteCommand( query, System.Data.CommandType.Text, null, commandTimeout );
       }
       catch ( System.Exception ex )
       {
           HttpContext context2 = HttpContext.Current;
           ExceptionLogService.LogException( ex, context2 );
           throw;
       }
   }
}

Job Settings

You’ll notice on the first line of the Execute method we’re setting a variable which is the JobDataMap object from the context’s JobDetail. With this object GetString() method you can fetch any administrator configurable Job settings you’ve added to your job. These settings are really just like the Block settings you’ve already learned about.

There are two settings in this job, one that holds the SQL the job will run, and a configurable timeout setting -- in case the SQL is expected to take a long time to execute:

[CodeEditorField( "SQL Query", "SQL query to run", CodeEditorMode.Sql, CodeEditorTheme.Rock, 200, true, "", "General", 0, "SQLQuery" )]

[IntegerField( "Command Timeout", "Maximum amount of time (in seconds) to wait for the SQL Query to complete. Leave blank to use the SQL default (30 seconds).", false, 180, "General", 1, "CommandTimeout")]

Simply pass the setting’s key to the GetString() method of the JobDataMap class to fetch the configured value as shown here:

string query = dataMap.GetString( "SQLQuery" );

When the value is expected to be a datatype other than a string, you can use one of Rock’s handy “As*” extension methods to get the datatype you’re expecting as seen here:

int? commandTimeout = dataMap.GetString("CommandTimeout").AsIntegerOrNull();

Result

One thing missing from this job something that lets the Job Scheduler know the results of the execution. These results are just a user friendly message that the admin can see in the “Last Status Message” on the Jobs Administration page. The message is simply set using the context.Result property. Here is an example from the SendBirthdayEmail job:

context.Result = string.Format( "{0} birthday emails sent", recipients.Count() );

Exceptions

It's also a good idea to wrap your execute code with a try-catch block. In the event that something goes wrong, you can log the exception using Rock’s logging service as seen here:

ExceptionLogService.LogException( ex, HttpContext.Current );

That’s really it. To get started just create a project named appropriately as per the Naming Conventions and create a class that extends IJob.

Last Step

Once you’ve created your project, remember to add a reference to the RockWeb project. See the Adding the Project to RockWeb chapter for those details.

Last updated