SharePoint: Developing Custom Timer Jobs


SharePoint Service Timer Jobs, perform units of work on a single or repeating schedule and can be thought of in the same way as Windows Services or Scheduled Tasks.

Developing custom Timer Jobs is relatively simple, you declare a class which derives from SPJobDefinition and overrides the Execute method as shown;

public class MySampleTimerjob : SPJobDefinition
{
	public const string JOB_DEFINITION_NAME = "MY_SAMPLE_TIMER_JOB";
	public const string JOB_DEFINITION_TITLE = "My Sample Timerjob";

	/// <summary>
	/// Initializes a new instance of the <see cref="MySampleTimerjob"/> class.
	/// </summary>
	public MySampleTimerjob()
	{
		Title = JOB_DEFINITION_TITLE;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="MySampleTimerjob"/> class.
	/// </summary>
	/// <param name="webApplication">The web application.</param>
	public MySampleTimerjob(SPWebApplication webApplication)
		: base(JOB_DEFINITION_NAME, webApplication, null, SPJobLockType.Job)
	{
		Title = JOB_DEFINITION_TITLE;
	}

	/// <summary>
	/// Executes the job definition.
	/// </summary>
	/// <param name="targetInstanceId">For target types of <see cref="T:Microsoft.SharePoint.Administration.SPContentDatabase"></see> this is the database ID of the content database being processed by the running job. This value is Guid.Empty for all other target types.</param>
	public override void Execute(Guid targetInstanceId)
	{
		var webApp = WebApplication;

		try
		{
			// add a new list item to the Tasks list of the first web of the first sitecol of the webapp
			using (var site = new SPSite(webApp.Sites[0].ID))
			using (var web = site.OpenWeb())
			{
				var list = web.Lists["Tasks"];
				var newItem = list.Items.Add();
				newItem["Title"] = GetType().Name + ": " + DateTime.Now;
				newItem.Update();
			}
		}
		catch
		{}
	}
}

This very simple sample, adds a new ListItem to the Tasks list of the root web of the 1st site collection of the web application the timer job is registered with.

Of note is the SPJobDefinition constructor (or constructors) which accept an SPJobLockType value. This parameter controls the locking behaviour of the Timer Job and can be one of the following values;

  • ContentDatabase – this options locks the content database associated with the web application, but the job will be run for each content database associated with the web application.
  • Job – Ensures that the job will be run only on a single server.
  • None – Ensures that the Job will be run on all servers.

Based on these options you must decide which value is correct for your tasks, but, for the most part the SPJobLockType.Job option is probably the most likely option to use.

The only other development tasks are to set the Timer Job title, using the Title property and obviously to implement the Execute method.

My own tips on developing a timer job are;

  • Develop your Timer Job class as a wrapper to the actual implementation code, which can be hosted within, say, a satellite assembly or a web service – the reason for this is that debugging a Timer Job is notoriously time consuming and generally not as straightforward as with other SharePoint deployed code. More on debugging later.
  • Deploy your Timer Job using a Web Application / Farm scoped feature.
  • Store your Timer Job configuration using the Hierarchical Object Store or the Object Property Bag.

Configuration.

Various options are available to use for storage of the Timer Jobs configuration data, Database, app.config, web.config etc. The most practical options however are to use either the Hierarchical Object Store or the Object Property Bag.

Both of these options are well supported in the current builds of the SharePoint Patterns and Practices Guidance.

Deployment.

There is no provision in CAML to deploy Timer Jobs, and the only way to do it is to write a few lines of code. Therefore a Feature with feature receiver is the perfect way to deploy your timer job, at either the Farm or Web Application scope.

In your feature receiver, register the timer job as shown;

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
	var webApp = properties.Feature.Parent as SPWebApplication;
	if (webApp == null) throw new Exception("webApp");

	// undeploy the job if already registered
	var ej = from SPJobDefinition job in webApp.JobDefinitions
		         where job.Name == MySampleTimerjob.JOB_DEFINITION_NAME
			select job;
	if (ej.Count() > 0)
		ej.First().Delete();

	// create and configure timerjob
	var schedule = new SPMinuteSchedule
		{
			BeginSecond = 0,
			EndSecond = 59,
			Interval = 5,
		};
	var myJob = new MySampleTimerjob(webApp)
		{
			Schedule = schedule,
			IsDisabled = false
		};

	// save the timer job deployment
	myJob.Update();
}

and to unregister the timer job;

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
	var webApp = properties.Feature.Parent as SPWebApplication;
	if (webApp == null) throw new Exception("webApp");

	// undeploy the timerjob
	var ej = from SPJobDefinition job in webApp.JobDefinitions
			where job.Name == MySampleTimerjob.JOB_DEFINITION_NAME
			select job;
	if (ej.Count() > 0)
		ej.First().Delete();
}

Once your feature is activated, you’ll see your Timer Job in the Timer Job Definitions page on Central Administration;

Timer Job Definitions
Timer Job Definitions

But it won’t appear on the Timer Job Status page until it has been executed at least once;

Timer Job Status
Timer Job Status

Debugging.

Unlike other development assets you’ll develop for SharePoint, Timer Jobs do not execute under the W3WP.exe process, but rather they execute under the OWSTIMER.exe process, which is the executable for the Windows SharePoint Service Timer service (SPTimerV3).

To debug a timer job, or when you rebuild a timer job;

  • Reset IIS
  • Restart the SPTimerV3 service (net stop SPTimerV3, net start SPTimerV3)
  • Rebuild your Timer Job Project
  • In Visual Studio, attach the debugger to the OWSTIMER process, check the “Show processes from all users” checkbox.
Attach the Visual Studio Debugger
Attach the Visual Studio Debugger
  • Set your breakpoints and when the Timer Job next executes your breakpoints should be hit.

It can sometimes be a bit hit and miss, actually getting the debugger attached correctly and your breakpoints being hit. Furthermore, the schedule used when the Timer Job is registered affects how often it is executed – for these and other reasons, debugging a Timer Job isn’t really a great experience.

Architecting your solution such that the timer job is a simple call though wrapper around the timer job implementation hosted in a satellite assembly or a web service will allow you much more flexibility in terms of unit testing and debugging, and greatly simplifies the development process.

A sample solution containing this timer job and a web application scoped feature for deployment can be found on my projects page.

Published by

Phil Harding

SharePoint Consultant, Developer, Father, Husband and Climber.

9 thoughts on “SharePoint: Developing Custom Timer Jobs

  1. Good post.
    I have a deployment problem. If you run it from visual studio, there’s no problem. But if I install the solution (wsp) whit a command shell the timer job’s installation fails.

  2. How do you deploy a timer job on a specific web application? when I use the -WebApplication in powershell script, it’s returning this error:

    “Install-SPSolution : This solution contains no resources scoped for a Web application and cannot be deployed to a particular Web application.”

  3. The solution has no web application scoped resources, which usually means there are no SafeControl entries to be made in the web apps web.config, if you really must deploy to specific web applications you could add a dummy class to your assembly which inherits from Control, this will force a SafeControl entry to be added to web.config – assuming you’re using WSPBuilder.

  4. How to use custom timer job scheduling in SharePoint 2010?
    The scheduling information like min,hours should be read from custom list in SharePoint site and using feature receiver we need to pull the information from list and update the timer job definition.
    How Can we read the site url and custom list url and send it to the feature receiver for updating the timer job definition? Attached the link for reference.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s