Thursday, May 16, 2013

Sharepoint 2010 Timer Jobs

In this article I am going to show how to make our timer job to run in the specified servers in the farm which is having Front end server or App server.

If we don't specify server then timer jobs will run in any of the front/app servers.

We have a requirement where we need to run our timer job only in app server since our timer job was making an web service call. You may think what's the wrong running timer job in front end server. Here ports(where we are making call to web service) were opened only in app servers not in FE servers.

Suppose if the timer job picks from front server then definitely it will throw exception in order to avoid this situation we change the logic to run only in app servers as shown below, before that I will give an overview of sharepoint timer jobs.

Sharepoint timer jobs should inherit from the SPJobDefinition class. This class provides 3 constructors for us:

SPJobDefinition()Default constructor needed for serialization purposes. Initializes a new instance of the SPJobDefinition class.
SPJobDefinition(String, SPWebApplication, SPServer, SPJobLockType) Instantiates a timer job associated with the given SPWebApplication. Initializes a new instance of the SPJobDefinition class and provides parameters for specifying key objects.
SPJobDefinition(String, SPService, SPServer, SPJobLockType) Instantiates a timer job associated with the given SPService. Initializes a new instance of the SPJobDefinition class and provides parameters for specifying key objects.

First constructor is required in any of the custom timer job and we can use either 2nd or 3rd constructor in our code but either one of them is mandatory(Job definitions must be associated with a service or Web application)

Sample code:

public class Sharepoint2010TimerJob : SPJobDefinition
{
     public Sharepoint2010TimerJob(): base()
     {
     }

     public Sharepoint2010TimerJob(string name, SPService service, SPServer server,      SPJobLockType lockType) : base(name, service, server, lockType)
     {
     }

     public Sharepoint2010TimerJob(string name, SPWebApplication webApplication, SPServer server,      SPJobLockType lockType) : base(name, webApplication, server, lockType)
     {
     }

     public override void Execute(Guid targetInstanceId)
     {     
             //Execute Timer Job Tasks
            //This is the place where we are making our web service call and doing executing the logic
     }
}

Below is our normal sharepoint job definition code now I will show how to make our timer service to run in the specified server.

Open the feature receiver class for our timer job.

     [Guid("{39ad45db-49a6-45d2-ae99-4cd677ecf65d}")]
     public class Sharepoint2010TimerFeatureReceiver :      SPFeatureReceiver
     {
    
              string timerJobName = "SharePoint 2010 Timer job";
    
              public override void FeatureActivated(SPFeatureReceiverProperties properties)
             {
                       SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
                
                      //Delete the job if it is already existing in our case this is not required we can comment the below line.
                      DeleteJob(webApp.JobDefinitions, timerJobName);

                     //Declare the SPServer object
                     SPServer serverToRunOn = null;

                    //Get all the servers in the farm
                    SPServerCollection servers = SPFarm.Local.Servers;

                   //Checking for property bag entry if it is already there then assign the value
                    if (webApp.Properties[timerJobName + "_Server"] != null)
                   {
                              serverToRunOn = servers[webApp.Properties[timerJobName + "_Server"].ToString()];
                    }

                 //Here we can check if form is configured with single server
                  if (serverToRunOn == null)
                  {
                           foreach (SPServer server in servers)
                           {
                                   if (server.Role == SPServerRole.SingleServer)
                                  {
                                           serverToRunOn = server;
                                           break;
                                   }
                            }
                    }
              
                   // if you want to run timer service in app server then below is the code we need to use
                   if (serverToRunOn == null)
                  {
                           foreach (SPServer server in servers)
                          {
                                   if (server.Role == SPServerRole.Application)
                                  {
                                             serverToRunOn = server;
                                             break;
                                  }   
                          }
                  }

                  // If we want to run the code in front end server then use the below piece of code.
                  if (serverToRunOn == null)
                 {
                          foreach (SPServer server in servers)     
                         {
                                if (server.Role == SPServerRole.WebFrontEnd)
                               {
                                         serverToRunOn = server;
                                         break;
                               }
                        }
                 }

               //In the above piece of code I am checking so many conditions and may be every one will think why so many conditions are required if I need to assign for only app server.

             //Here is my answer lets assume we need to deploy the code in dev server where its running in single server then 1st condition will be useful

            //If we move the code to staging environment which is running with multiple server but no dedicated app server then we require 3rd condition
    
           //If we move the code to ppe(pre production environment) which is replica of Prod then it will have proper sharepoint set up like 2 front end, 1 app server , 1 db server(small farm) then 2nd condtion will execute.

          //This is what we are looking to run the timer job to run in app server.
        
          // Define the schedule
          Sharepoint2010TimerJob timerJob = new Sharepoint2010TimerJob(timerJobName, webApp, serverToRunOn, SPJobLockType.Job);

          webApp.Properties[timerJobName + "_Server"] = serverToRunOn.Name;

          //Schedule as per the requirement
          SPMinuteSchedule minuteSchedule = new SPMinuteSchedule();
          minuteSchedule.BeginSecond = 1;
          minuteSchedule.EndSecond = 59;
          minuteSchedule.Interval = 10;
          timerJob.Schedule = minuteSchedule;
          // Update the schedule      timerJob.Update();
       }
  }
}

No comments:

Post a Comment