Contact Us

Use the form on the right to contact us.

You can edit the text in this area, and change where the contact form on the right submits to, by entering edit mode using the modes on the bottom right. 

           

123 Street Avenue, City Town, 99999

(123) 555-6789

email@address.com

 

You can set your address, phone number, email and site description in the settings tab.
Link to read me page with more information.

All about SharePoint Work Item Timer Jobs

Blog

Designing solutions on the SharePoint and Office 365 platforms.

All about SharePoint Work Item Timer Jobs

Eric Gregorich

If you asked me how to use a Work Item Timer Job just 6 months ago I would have responded "What the heck is a Work Item Timer Job"? It turns out that Work Item Timer Jobs have existing since SharePoint 2010 (at least). I discovered them myself just a short time ago while doing research for a new business application I was implementing.

What is a Work Item Timer Job?

You probably know what a regular timer job is. It runs on a schedule and performs infrastructure tasks in SharePoint. A timer job may clean up content, perform synchronization,  or run other operations on data stored in SharePoint. You can create your own timer jobs as well if you had a need to run code on a regular schedule.

So what is a Work Item Timer Job? It turns out, it is almost the same thing. It can be scheduled to run operations in SharePoint. The difference is that a Work Item Timer Job is essentially a queue where you add list items that need to be processed. When the Work Item Timer Job runs, it pulls items from the queue and process the item. When complete, the item is removed from the queue (if you want) so it is not processed again. 

Why use a Work Item Timer Job?

When I discovered Work Item Timer Jobs I was looking for the best way to run long-running operations on items added to a SharePoint list. In my case, I was collecting information from users and using this information to create new site collections. When the site collection is created it would set permissions, update a site collection directory and a few other things. When the process was complete, I would change the status of the request list item. I didn't want the user who created the request to have to wait for the process to complete before they could leave the request form. I also wanted to schedule the site collections to be created after hours so we could comply with governance policies. 

The Work Item Timer Job turned out to be a great solution for this. It allowed me to separate the collection of data from the actual heavy processing that needed to occur. And I did this without writing any queries! Overall it was much simpler to implement in my opinion. When the request list item was saved, a simple event receiver creates a Work Item. When the Work Item Timer Job runs after hours, it processes my Work Item. Pretty simple!

Step 1: Creating the Work Item Timer Job

First you'll need to create the timer job. This is nearly the same as creating a normal Timer Job only you want to derive from SPWorkItemJobDefinition rather than SPJobDefinition. The big difference is the BatchFetchLimit (how many work items do you want to process at once) and the ProcessWorkItem method which is run automatically for each Work Item in the queue.

 using System;  
 using System.Linq;  
 using Microsoft.SharePoint;  
 using Microsoft.SharePoint.Administration;  
 namespace Demo.CustomTimerJobs  
 {  
   public class CustomWorkItemTimerJob: SPWorkItemJobDefinition   
   {  
     public static readonly string WorkItemJobDisplayName = "Custom Work Item Timer Job";  
     public static readonly Guid WorkItemTypeId = new Guid("{CEAAFFA4-4391-40D6-868E-19EDEDB78DD4}");  
     public CustomWorkItemTimerJob: ()  
     {  
     }  
     public CustomWorkItemTimerJob: (string name, SPWebApplication webApplication) : base(name, webApplication)  
     {  
     }  
     public override int BatchFetchLimit  
     {  
       get  
       {  
         return 50;  
       }  
     }  
     public override string DisplayName  
     {  
       get  
       {  
         return WorkItemJobDisplayName;  
       }  
     }  
     public override Guid WorkItemType()  
     {  
       return WorkItemTypeId;  
     }  
     protected override bool ProcessWorkItem(SPContentDatabase contentDatabase, SPWorkItemCollection workItems, SPWorkItem workItem, SPJobState jobState)  
     {  
       if (workItem == null) throw new ArgumentNullException("workItem");  
       using (SPSite site = new SPSite(workItem.SiteId))  
       {  
         using (SPWeb web = site.OpenWeb(workItem.WebId))  
         {  
           try  
           {  
             SPList list = web.Lists[workItem.ParentId];  
             SPListItem listItem = list.GetItemByUniqueId(workItem.ItemGuid);  
             // Run any code you want against your listItem.  
           }  
           finally  
           {  
                // Clear this work item from the queue so it is not processed again.  
             workItems.SubCollection(site, web, 0, (uint)workItems.Count).DeleteWorkItem(workItem.Id);  
           }  
         }  
       }  
       return true;  
     }  
   }  
 }  

Step 2: Adding a new Work Item

Now that you have a timer job created, you need to add work items. When you create the work item, you associate it with your custom timer job. This means only your timer job can process your work items. Or you could even create multiple timer jobs to process different types of work items.

Work items are added at the site collection level using the SPSite.AddWorkItem method. This adds the work item to the SharePoint database. When the timer job runs, it will grab all of the work items in this queue for processing. You can create the work item from anywhere, but in my example I'm creating it within an Event Receiver that runs on my list. 

 using System;  
 using Microsoft.SharePoint;  
 namespace Demo.CustomTimerJob  
 {  
   public class CustomEventReceiver : SPItemEventReceiver  
   {  
     public override void ItemUpdated(SPItemEventProperties properties)  
     {  
        Guid siteId = properties.SiteId;  
       Guid webId = properties.Web.ID;  
       Guid listId = properties.ListId;  
       int itemId = properties.ListItemId;  
       Guid itemUniqueId = properties.ListItemUniqueId;  
       int currentUserId = properties.CurrentUserId;  
       SPSecurity.RunWithElevatedPrivileges(() =>  
       {  
         using (SPSite site = new SPSite(siteId))  
         {  
               site.AddWorkItem(Guid.NewGuid(),  
             DateTime.Now.ToUniversalTime(),  
             SiteProvisioningTimerJob.WorkItemTypeId,  
             webId,  
             listId,  
             itemId,  
             true,  
             itemUniqueId,  
             itemUniqueId,  
             currentUserId,  
             null,  
             "Pass this message to the timer job.",  
             Guid.Empty);  
         }  
       });  
     }      
   }  
 }  

Other Tips

  • The user adding the work items must be a Site Collection Administrator.
  • The code adding the work item must have full trust.
  • You should delete the work item after you run your code against it, unless of course you want the item to be processed every time the timer job runs.

Conclusion

The Work Item Timer Job is a great addition to a SharePoint developers arsenal. It can definitely be used to solve many problems. Here are some other ideas of where this may be a good solution:

  1. Provisioning site collections or sites.
  2. Copying list data into a SQL Database so it can be used for more robust reporting.
  3. Executing external services that may do very specific processing of the list item data or documents added to SharePoint.

When would you use a Work Item Timer Job?