RSS Feed Feed your read!

Scot Hillier is an independent consultant and Microsoft SharePoint Most Valuable Professional focused on creating solutions for Information Workers with SharePoint, Office, and related .NET technologies. A frequent speaker at TechEd and SharePoint Connections, he is also the author many books on Microsoft technologies including 5 for SharePoint 2010. Scot splits his time between consulting on SharePoint projects and training for Critical Path Training. Scot is a former U. S. Navy submarine officer and graduate of the Virginia Military Institute. Scot can be reached at scot@shillier.com

Archives

January 2010 (17)
February 2010 (1)
March 2010 (1)
April 2010 (2)
May 2010 (1)
June 2010 (1)
August 2010 (4)
September 2010 (6)
October 2010 (3)
November 2010 (2)
February 2011 (1)
March 2011 (4)
April 2011 (3)
May 2011 (1)
August 2011 (1)
March 2012 (1)
April 2012 (1)
July 2012 (3)
August 2012 (1)
September 2012 (1)
October 2012 (2)
November 2012 (3)
January 2013 (2)
February 2013 (3)
March 2013 (3)
April 2013 (3)
May 2013 (1)
September 2013 (2)
November 2013 (5)
January 2014 (2)
February 2014 (2)
March 2014 (1)
April 2014 (1)
May 2014 (1)

Links

IT Unity
SharePoint Team Blog
Andrew Connell's Blog

Tag Cloud

Apps, Books, Business Data Connectivity, Claims, Conferences, JavaScript, jQuery, MOSS 2007 Archived Post, PowerShell, REST and CSOM, Search, SharePoint 2010, SharePoint 2013, Web Content Management,

Where is My Timer Job? 

Tags: MOSS 2007 Archived Post

SharePoint Timer Jobs are great for accomplishing tasks asynchronously throughout the farm. You can create your own custom Timer Job by inheriting from SPJobDefinition. Recently a question arose regarding the exact nature of custom Timer Job execution. Specifically, which servers in the farm actually run the Timer Job?

Well, it turns out to be a pretty simple answer. The SPJobDefinition class has a property called LockType. When set to SPJobLockType.Job then the job only runs on the server where the job was submitted. If the value is SPJobLockType.None, then the job runs on every server in the farm.

Creating a Test Timer Job

In order to test out the various LockType values, I created a simple Timer Job that does nothing except increment a value in a database table. The idea is that a single field in a single database table would be incremented by all Timer Job instances. This way, I could count the number of times the job ran in the farm. My test farm had 2 web front end servers and a single application server.

 

Creating the Timer Job itself was reasonably straightforward. I created a new class that inherited from SPJobDefinition. Within the class, I could set the LockType property for the various tests. I also included a SubmitJob() method for submitting a new Timer Job instance. The following code shows the Timer Job I created, and you can download the complete code here. Note the value for the LockType property.

public class Ticker : SPJobDefinition
{
    public Ticker() : base() { }
    public Ticker(string jobName, SPWebApplication webApplication)
        : base(jobName, webApplication, null, SPJobLockType.Job)
    { this.Title = "Ticker"; }

    const string CONNECTION_STRING = "Server=MySQLServer\\MOSS_SQL2K5;Database=Jobs;Trusted_Connection=yes;";

    public override void Execute(Guid targetInstanceId)
    {
        try
        {
            using (SqlConnection conn = new SqlConnection())
            {
                conn.ConnectionString = CONNECTION_STRING;
                conn.Open();

                SqlCommand command = conn.CreateCommand();
                command.CommandType = CommandType.Text;
                command.CommandText = "UPDATE Ticks SET Count = Count + 1";
                command.ExecuteNonQuery();

                conn.Close();

            }
        }
        catch (Exception x)
        {
            TraceProvider.RegisterTraceProvider();
            TraceProvider.WriteTrace(TraceProvider.TagFromString("Ticks"), TraceProvider.StringToSeverity("Exception"), Guid.NewGuid(), "Execute", "TimerJobCounts", "Test", x.Message);
            TraceProvider.UnregisterTraceProvider();
        }
    }

    public void SubmitJob()
    {
        Schedule = new SPOneTimeSchedule(DateTime.Now);
        Title = "Ticker (" + (new Guid()).ToString() + ")";
        Update();
    }
}

 

Testing the Timer Job

Once the Timer Job class was created, I installed it into the GAC on each of the three servers in the farm. Then I created a simple console application to submit new job instances. The following code shows the console application.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            SPWebApplicationCollection webApps = SPWebService.ContentService.WebApplications;

            TimerJobCounts.Ticker ticker = new TimerJobCounts.Ticker(args[0], webApps[args[1]]);
            ticker.SubmitJob();
        }
        catch (Exception x)
        {
            Console.WriteLine(x.Message);
            Console.WriteLine("First argument is a Title for the job.");
            Console.WriteLine("Second argument is Name of Web Application");
            Console.WriteLine("");

            SPWebApplicationCollection webAppCollection = SPWebService.ContentService.WebApplications;
            foreach (SPWebApplication webApp in webAppCollection)
            {
                Console.WriteLine(webApp.Name);
            }

        }
    }
}

For the tests, I first ran the Job Compiled with the LockType set to Job. I manually set the database value to zero, and then ran the Timer Job using the Console Application. The Timer Job immediately appeared in the list of scheduled jobs.

 

After the job ran, I checked the database, and sure enough the count had been incremented to 1. This confirmed that the job ran only on the server where it was submitted - that it the server where I ran the console application.

For the next test, I recompiled the Timer Job with the LockType set to None. After deploying the assembly again to the GAC on every server, I cleared the database value back to zero, and reran the job. This time the database value was incremented to 3 after the job ran, indicating that the job ran on every server in the farm.

 

Conclusion

When creating a custom Timer Job, you must decide whether you want the job to run only once for the farm or once on every server. Jobs that update files in the 12 directory, for example, generally need to run on every server. On the other hand, jobs that update a database may only need to run once.

 
Posted by Scot Hillier on 18-Jan-10
0 Comments  |  Trackback Url  |  Link to this post | Bookmark this post with:        
 

Links to this post

Comments