SharePoint: timer jobs and history and status
History in SharePoint jobs
Timer jobs are a convenient way to perform background tasks in SharePoint. This article organize some facts about the history of the timer jobs. The following facts are true for SharePoint 2010, but most of them should be valid for other versions of SharePoint.
History of a timer job is a collection of entries that contain the information about:
- Job’s name
- Job’s start time
- Job’s end time
- Job’s result (status code)
- Some UUID’s to identify server, web application, job, service etc.
Those information allow us to see some abnormalities in the duration or status of the job should they occur one day.
History entries are only written for jobs that has finished executing. This means that there are no history entries for the jobs currently running. One of the consequences is that you can’t use history to list the jobs that are running but has not finished yet.
Where and how long is timer job’s history stored
According to MSDN documentation, job history is stored for 7 days. The static class SPDeleteJobHistoryJobDefinition
provides some configuration for the job history via Object Model properties, including the setting of number of days the history is stored.
In SharePoint 2010 history entries are stored in central administration’s database table TimerJobHistory
(see fig. 1). While it’s considered a bad practice to access SharePoint contents directly via SQL, this might be the easiest way for some analytic purposes like exporting the history to CSV file.
The proper and supported way to access data about job history is via the SPJobDefinition
‘s property called HistoryEntries
. The next section show some simple example of this property.
Example: When was the last time a job was running?
The following example obtains the information about the time of last successful run of a timer job. It could be written more concisely, but it’s aim is to show how to iterate timer jobs in SharePoint’s Object model and use HistoryEntries
property. Comments are added to further explain the subject.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
/// <summary> /// Return the last EndTime of a *successful* execution of a SharePoint timer job, based on job history (if present). /// Please mind, that the history is only stored for a limited number of days (by default 7). /// Sources: /// * http://reality-tech.com/2012/11/24/timer-job-history/ /// * http://social.technet.microsoft.com/Forums/sharepoint/en-US/7b57a7cc-a5f7-4255-9398-7b5ba2c0fa4f/delete-timer-job-history-looking-for-settings /// </summary> /// <param name="jobTitle">Title of a job to check</param> /// <returns>if the date can be obtained from the history, returns EndDate of the last run of a given job. Otherwise returns null.</returns> public Nullable<DateTime> GetTimerJobLastEndTime(string jobTitle) { List<DateTime> successDates = new List<DateTime>(); var allJobs = GetAllJobs(); foreach (SPJobDefinition job in allJobs) { if (job.Title.Equals(jobTitle)) { foreach (var e in job.HistoryEntries) { // please mind, that the entries are only added to history entries when the job ends (regardless of the result) // therefore, changing the condition e.g. to SPRunningJobStatus.Initialized will *not* give you the list of running jobs // (they are not yet present in the HistoryEntries). // To get the list of running jobs, use SPFarm.Local.Services.(Service).RunningJobs collection if (e.Status == SPRunningJobStatus.Succeeded) { successDates.Add(e.EndTime); } } } } return successDates.Count == 0 ? null : new Nullable<DateTime>(successDates.Max()); } /// <summary> /// Return all job definitions on the local SharePoint farm, both Service Application jobs and Web Application jobs. /// </summary> /// <returns>Collection of job definitions in the local farm</returns> private List<SPJobDefinition> GetAllJobs() { var timerJobs = new List<SPJobDefinition>(); SPSecurity.RunWithElevatedPrivileges(() => { // "Each timer job is either associated with a SharePoint Service Application or a SharePoint Web Application." // source: http://www.c-sharpcorner.com/UploadFile/d2ee01/sharepoint-2010-internals-timer-jobs2/ foreach (SPService localService in SPFarm.Local.Services) { // list all SharePoint Service Applications jobs foreach (var job in localService.JobDefinitions) { timerJobs.Add(job); } // check whether service is of a SPWebService type and therefore might contain web applications if (localService is SPWebService) { var webService = (SPWebService)localService; // iterate all Web Applications foreach (SPWebApplication webApp in webService.WebApplications) { // list all Sharepoint Web Application jobs foreach (SPJobDefinition job in webApp.JobDefinitions) { timerJobs.Add(job); } } } } }); return timerJobs; } |
Timer Job history can also be managed via PowerShell if you prefer.
If you are interested in accessing information about the currently running jobs rather than those from the past, you might also want to read SharePoint: list running timer jobs (C#). Good luck!