Wednesday, October 8, 2008

Custom SharePoint Timer Jobs


This post certainly doesn’t walk you through the steps of authoring a custom SharePoint timer job.  It does highlight one issue I ran into though while I was building one recently that seems to be a plain old bug.  After struggling with it for some time, I thought I’d drop a quick post with the hopes it will save someone else the headache! 

The structure of a customer timer job is actually pretty simple – you need a class that inherits from “SPJobDefinition,” that overrides a few constructors as well as the Execute() method.  The Execute() method defines what actually happens when your timer job elapses and gets fired. 

To install your timer job and register in Central Admin, you need a FeatureReceiver.cs class.  It’s not in the scope of this brief post to go through the details of the FeatureReceiver class (but of course email me if you’re stuck!).  The FeatureReceiver for my timer job overrides the “FeatureActivated” and “FeatureDeactivating” events.  The area that was giving me trouble was in the “FeatureActivated” event.  I wanted my timer job to run once per day at 1:45 am.  The code looked something like this:

// Install the job
AggregatorTimerJob aggregatorTimerJob = new AggregatorTimerJob(site.WebApplication);

// Set the schedule - run once daily
SPDailySchedule dailySchedule = new SPDailySchedule();
dailySchedule.BeginHour = 1;
dailySchedule.BeginMinute = 45;
dailySchedule.BeginSecond = 0;

aggregatorTimerJob.Schedule = dailySchedule;
aggregatorTimerJob.Update();


Seems simple enough!  However after hours of experimenting with the SPDailySchedule, and searching for answers, I simply could NOT get this thing to run on a daily schedule.  Most frustrating was that using an “SPMinuteSchedule” or “SPHourlySchedule” worked beautifully!

After much searching I finally concluded that using the “SPDailySchedule” approach seems to universally fail – that seemed to be the consensus amongst the community. 

So … the Workaround

I think this is an easier, more straight-forward approach anyway, so I hesitate to call it a “work-around” at all!  I ended up using the “SPCustomSchedule” class and defining its run schedule as a free-form string parameter as follows.  Works like a charm – on my environment, all the way through production without any issues!

SPSchedule customSchedule = SPSchedule.FromString("daily at 01:45");

aggregatorTimerJob.Schedule = customSchedule;
aggregatorTimerJob.Update();

3 comments:

Unknown said...
This comment has been removed by the author.
Unknown said...

using an “SPMinuteSchedule” or “SPHourlySchedule” worked beautifully

Every example I've seen of SPMinuteSchedule uses a factor of 60 as its interval, so nobody notices that it resets every hour. Try setting it to a value like 45 or 90, and you'll see that it resets every hour. Have other people experienced this? Does anybody know a workaround?

Unknown said...

Using "SPDailySchedule" is pretty simple, you need to set an interval like in administration page.
So you need to set when it can start between "Begin" (BeginHour/BeginMinute/BeginSecond) and "End" (EndHour/EndMinute/EndSecond). Note that end time must be after than begin time.