As a single unified logical entity, a SharePoint farm requires a mechanism to run tasks necessary to provide its services. These tasks include updating components of the farm such as servers and services, and updating data and configuration in farm databases. To run these tasks, SharePoint provides its own scheduled tasks management service, manifested as Timer Service instances installed on every SharePoint server in the farm. If the Timer Service or any of its instances on servers begins to malfunction, it won't take long for problems to begin appearing across the farm. For all its importance, though, the Timer Service is often misunderstood. In this blog post we'll explore the basic elements and startup process of the SharePoint Timer Service. In the future and as time permits, we'll further explore the Timer Job system and many of the specific Timer Jobs which run in a farm.
When the Timer Service Instance on a server starts up, it must first configure its local store of timer jobs to be run and initialize other timer service settings. You can follow along with this procedure in the ULS logs (perhaps by using a personal favorite, ULSViewer) by filtering for the SharePoint Foundation/Timer category. Most useful messages are of severity Medium, a few are Verbose. The first message in the sequence is simply, "The Timer Service is starting." (duh-duh-duh)
To understand the Timer Service, we must now stop to explain Timer Job Definitions. Timer Job Definitions are .NET classes which describe and define the actions which a Timer Job will take. All timer job definitions derive from the SPJobDefinition class. In fact, when running the PowerShell Get-SPTimerJob cmdlet, objects of type SPJobDefinition are returned. Writing custom timer jobs requires creating a new class derived (directly or indirectly) from SPJobDefinition and overriding the Execute() method with job-specific procedures.
In order for a timer job to be run, an instance of it must be associated with a service or web application in the farm. Every service and web application has a collection of job definitions associated with it. These job definitions are executed by the Timer Service wherever the associated service or web application has been provisioned. So, as this implies, after a job definition class derived from SPJobDefinition is created, an instance of the class must be added to the JobDefinitions collection of a service or web application in the farm.
For a given service or web application, retrieve all associated job definitions by accessing the JobDefinitions property, for example:
$svc = Get-SPEnterpriseSearchService$svc.JobDefinitions $webapp = Get-SPWebApplication | Select-Object -First 1 $webapp.JobDefinitions
With Job Definitions explained, we can now explain the initialization of the Timer Service. The first step is to determine those services which have online service instances on the server where this instance of the Timer Service is being started. For those not familiar with the service/service instance concept in SharePoint, services are logical entities installed to the farm, while service instances are server-specific aspects of the service deployed to individual servers. While a service may exist in the farm, many cannot fully function without online service instances on individual servers.
The list of service instances installed on a given server can be retrieved manually by running Get-SPServiceInstance -Server $env:COMPUTERNAME. Some of these installed service instances will be online, some will be disabled. To understand this better, think of standard Windows services - all Windows services are installed on a given machine, but not all are online and running. In the same vein, while many SharePoint service instances may be installed on a server, only a subset will actually be online and running. The service instances which are online on this server are the ones who's parent service's associated job definitions will be run by this server's Timer Service.
To sum up, when the Timer Service on a server is initialized, services which have an online service instance on that server have their jobs registered to run on the server. Simple, yes? You'll see a clue to this in the ULS logs which come after the "Timer Service is starting" message; there will be a number of them immediately afterwards which state, "Service <Service_Type>, id <Service_Id> not online, ignoring". No timer jobs from that service for you! After the offline service instances are listed and ignored, online service instances are listed: "Processing service <Service_Type>, id <Service_Id>", followed immediately by the list of Job Definitions loaded from that service: "Add job definition <Job_Type>, id <Job_Id>".
Any server running the SPWebService (SharePoint Foundation Web Application service) runs all Web Application-associated jobs. Generally these are jobs which run against content databases; beginning with SharePoint 2010, there are ways to configure specific servers to process jobs for specific content databases, something we may explore in a later post.
If you'd like to see all timer jobs installed in your farm together with their associated services and web applications (where applicable), simply run this PowerShell command:
Get-SPTimerJob | Format-Table Name, Service, WebApplication
Once all relevant job definitions for this server have been identified, the final step in initializing the Timer Service is scheduling them all to be run (or attempted for run) at their next designated interval. You won't see the scheduling log entries in the ULS unless you turn up logging for the Timer category to Verbose. If you do, after the previous entries you'll find an entry for every identified job definition informing you of when it is next scheduled to be run.
At this point your Timer Service is up and ready to run jobs! Look for more info on the Timer Service and Timer Jobs in future posts.
I cant get my custom timer to run.
I noticed the following entry.
Job definition "Timer Job definition ID" has no online instance for service Microsoft.SharePoint.Administration.SPWebService, id 76ebd71b-d996-453b-bb14-09a567a778b5, ignoring