December 12, 2011 6 Comments
I recently learnt about a new (well new to me at any rate) type of SharePoint timer job. Rather than the standard timer jobs I normally create that inherit from SPJobDefinition, this different kind of timer job inherits from SPWorkItemJobDefinition http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spworkitemjobdefinition.aspx
With a normal SharePoint timer job (SPJobDefinition), the job is scheduled via an SPSchedule object, and is run whenever this schedule dictates. When an occurrence of the timer job runs, any logic that is contained in the Execute method is then called:
So far, so normal. However, it is a fairly common requirement for a site collection to want a timer job to process something on its behalf – after all this what timer jobs excel at. However, communicating to the timer job what needs to be processed is usual done by creating custom list items (or some other content) in the site collection. Then the timer job has to iterate through the site content to find the items and then start performing some work based on those items or their properties.
I’ve done this myself and seen it done dozens of times and it usually involves hidden lists or custom columns on list items that the timer jobs is trained to look for.
Here’s where SPWorkItemJobDefinition timer jobs comes in. These timer jobs use a queue to determine what should be processed and the site collection simply adds items to the queue. No custom hidden lists, no custom columns, just a nice simple FIFO queue we can write too from the site collection .
How it works
Create a timer job that inherits from SPWorkItemJobDefinition:
…override the WorkItemType property with a unique Guid of your choosing:
…the WorkItemType is a unique Guid that this timer job will ‘listen’ for. Any operations that add SPWorkItems to the queue from the site collection will include a reference to this Guid. In this way, multiple timer jobs can share the same queue and SPWorkItems are picked up by the right timer jobs.
Next we override the ProcessWorkItem method, this is where we do our main processing and is the equivalent of the Execute method of a normal SPJobDefinition timer job:
This method is called by the timer job framework on each occurrence of the timer job schedule AND ONLY IF work items have been queue for this timer job based on its WorkItemType Guid. Because this method is only called when items are queued for it and the method is passed the work items to process rather performing expensive queries looking for items within the site collection, this is potentially a much more efficient operation compared to a standard timer job!
Note: Checkout the ProcessWorkItems method if you want to process multiple items in a single method call
So far we’ve created a new SPWorkItemJobDefinition timer job, assigned it a unique WorkItemType and overridden the main timer job processing logic in the ProcessWorkItems method. Next, we’ll create a simple web part to add SPWorkItems to the scheduled work items queue. This is a simple operation but provides some great flexibility, the following code illustrates the properties of the SPSite.AddWorkItem method we will call:
…the properties we set on the SPSite.AddWorkItem method should be fairly obviously but I think the schdDateTime parameter that allows us to add an item to the queue but schedule it to processing at some future point in time and the rgbBinaryPayload byte array parameter are particularly interesting.
Once the timer job and web part are deployed, here’s how it functions; when the web part is added to a page it will generate a new work item with a unique Guid:
The results of the SPSite.AddWorkItem call can be seen in the dbo.ScheduledWorkItems table in the site collections content database:
…don’t go poking around in the database – I’m just illustrating the process. I’ve then set a break point on the ProcessWorkItem method of our timer job:
When our timer job schedule occurs, our ProcessWorkItems method is called (ONLY IF items are queued for it) and the work item we added in the site collection is available to us for processing.
I’m now off to refactor half the timer jobs I’ve ever written and remove lot’s of hidden lists and columns.
If you want to download the solution I’m using in this article, it is available here: SPWorkItemJobDefinition.zip
I hope this helps…