As TFS runs in the background, there is always a requirement to run scheduled jobs that perform a batch operation silently in the background. The TFS Background Job Agent is used to run certain tasks that can be hooked into the TFS system and that run automatically when scheduled.
Before getting started, create a library
class and name it ScheduledJobs
. We need to add a reference to the following files:
Microsoft.TeamFoundation.Framework.Server.dll
located at C:Program FilesMicrosoft Team Foundation Server 12.0Application TierWeb ServicesBin
Microsoft.TeamFoundation.Common.dll
located at C:Program Files (x86)Microsoft Visual Studio 12.0Common7IDEReferenceAssembliesv2.0
Microsoft.VisualStudio.Services.WebApi.dll
located at C:Program Files(x86)Microsoft Visual Studio 12.0Common7IDEReference Assembliesv4.5
Once the setup is ready, let's write the scheduler logic first and later hook it into the TFS system.
We also create a new .NET 4.5 library class called TFS.ScheduledJobs
and add a reference to the following files:
Microsoft.TeamFoundation.Framework.Server.dll
located at C:Program FilesMicrosoft Team Foundation Server 12.0Application TierWeb Servicesin
Microsoft. TeamFoundation.Common.dll
located at C:Program Files (x86)Microsoft Visual Studio 12.0Common7IDEReferenceAssembliesv2.0
Microsoft.VisualStudio.Services.WebApi.dll
located at C:Program Files (x86) Microsoft Visual Studio 12.0Common7IDEReferenceAssembliesv4.5
We will be writing the ScheduledJob
logic inside the library
class and will later hook it to the main job project to run it.
Now let's create ScheduledJob
inside TFS using these simple steps:
IdCheckJob
and make it inherit variables from ITeamFoundationJobExtension
. Then implement the interface. This should now give you the following code:using System; using Microsoft.TeamFoundation.Framework.Server; namespace TFS.ScheduledJobs { public class IdCheckJob : ITeamFoundationJobExtension { public TeamFoundationJobExecutionResult Run(TeamFoundationRequestContext requestContext, TeamFoundationJobDefinition jobDefinition, DateTime queueTime, out string resultMessage) { throw new NotImplementedException(); } } }
Run
method, as shown in the following code. The idea is to check every work item and then check which work items have been updated:try { TfsTeamProjectCollection tfsServer = new TfsTeamProjectCollection(GetTFSUri(requestContext)); WorkItemStore workItemStore = tfsServer.GetService<WorkItemStore>(); List<WorkItem> changedWorkItems = new List<WorkItem>(); foreach (WorkItem workItem in workItemStore.Query("SELECT * FROM WorkItems")) { if (!workItem.Title.StartsWith("#" + workItem.Id + " - ")) { workItem.Title = "#" + workItem.Id + " - " + workItem.Title; changedWorkItems.Add(workItem); } } if (changedWorkItems.Count > 0) { workItemStore.BatchSave(changedWorkItems.ToArray()); resultMessage = changedWorkItems.Count + " work item titles updated."; } else { resultMessage = "no work item titles to update."; } return TeamFoundationJobExecutionResult.Succeeded; } catch (Exception ex) { resultMessage = "Job Failed: " + ex.ToString(); EventLog.WriteEntry("TFS Service", resultMessage,EventLogEntryType.Error); return TeamFoundationJobExecutionResult.Failed; }
The code selects the updated work items and updates the database with a message.
You can see that the resultMessage
variable is also updated so that we can see the job history.
.dll
and .pdb
files in C:Program FilesMicrosoft Team Foundation Server 12.0Application TierTFSJobAgentPlugins
.var tfsUri = new Uri("http://localhost:8080/tfs"); var config = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri); var jobService = config.GetService<ITeamFoundationJobService>(); var jobDefinition = new TeamFoundationJobDefinition("Check WorkItem Job", "TFS.ScheduledJobs.IdCheckJob"); jobDefinition.EnabledState = TeamFoundationJobEnabledState.Enabled; jobDefinition.Schedule.Add(new TeamFoundationJobSchedule(DateTime.Now,300)); jobService.UpdateJob(jobDefinition);
The code will retrieve the job that has been added as a plugin to the TFS job agent and we call UpdateJob
to service the plugin.
select * from Tfs_Configuration.dbo.tbl_JobDefinition where JobName = 'Check WorkItem Job'
If you see an entry that exists in the database, this means the job is running.
JobId
from the data and select JobHistory
to verify how the scheduled job is working, as shown in the following code:select * from Tfs_Configuration.dbo.tbl_JobHistory WITH (NOLOCK) where JobId = '62FDDA25-4938-4BF7-A7C3- 6A9BF527A20C
For instance, in my case it gives the appropriate results.
var tfsUri = new Uri("http://localhost:8080/tfs"); var config = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri); var jobService = config.GetService<ITeamFoundationJobService>(); jobService.DeleteJob(new Guid("62FDDA25-4938-4BF7-A7C3- 6A9BF527A20C"));
Here, you can see that I used the Guid
to identify the job rather than using the name. The DeleteJob
method will de-register the job from the TFS job agent.
TFS is hosted using IIS. There is a specific TFS job agent associated with the TFS, which runs periodically in the background to perform some batch operations. The TFS provides a plugin model to integrate your own scheduled tasks so that when the jobs are being dispatched, it can also run the user code automatically.
Until and unless the job has been deregistered, the TFS automatically picks it up and performs the tasks assigned to it.
18.191.215.96