Team Foundation Server 2013 的非确定性构建服务器行为

Nondeterministic build server behavior with Team Foundation Server 2013

随着我们团队的成长,对构建服务器的需求也在增长,直到它最终成为我们解决的一个项目。

我们有一个主项目,在提交到开发分支后排队等待自动部署。问题是构建服务器可以排队相同的构建、相同的修订并得到截然不同的结果。有时我们得到一个干净的构建,按预期部署到我们的测试服务器。在其他时候,我们可以将构建排队并获得 "Unable to copy file C:\Builds24\Project Name\Container Build\bin\somerandomreference. Access to the path C:\Builds24\Project Name\Container Build\bin\somerandomreference is denied".

或者我们得到:无法复制文件 "Scripts\somerandom.js" 因为找不到。

或者我们得到 "Could not copy ...EntityFrameWork.XML" 因为它正被另一个进程使用。

这些让我相信问题出在我们的构建重叠上,因此我们设置了队列以添加额外的提交,直到较早的构建完成。

唯一的防病毒软件是构建服务器 运行 Windows 8.1 机器上的默认 Microsoft Windows Defender。最初我们排除了构建文件夹,现在我们将其完全关闭。

没有人使用这台机器,它专用于构建服务器角色,不运行其他软件,只包含我们构建过程所需的安装。

我是否遗漏了构建服务器的任何最佳实践?我是否过于乐观地期望构建服务器应该以可重现的方式构建源的相同分支和版本(即使它是可重现的失败)?

更新:删除整个构建文件夹并重新设置后,我们得到这个(解决方案编译零错误,但没有测试结果或输出):

Exception Message: Error HRESULT E_FAIL has been returned from a call to a COM component. (type COMException)
Exception Stack Trace:    at Microsoft.TeamFoundation.WorkItemTracking.Client.DataStore.DataStoreNative.BeginDataStoreInit(IntPtr handle, String defaultCachePath, String instanceId, Int32 cacheVersion)
   at Microsoft.TeamFoundation.WorkItemTracking.Client.DataStore.Datastore.BeginDataStoreInit(String defaultCachePath, String instanceId, Int32 cacheVersion)
   at Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore.InitializeInternal()
   at Microsoft.TeamFoundation.Client.TfsTeamProjectCollection.InitializeTeamFoundationObject(String fullName, Object instance)
   at Microsoft.TeamFoundation.Client.TfsConnection.CreateServiceInstance(Assembly assembly, String fullName)
   at Microsoft.TeamFoundation.Client.TfsConnection.GetService(Type serviceType)
   at Microsoft.TeamFoundation.Client.TfsConnection.GetServiceT
   at System.Activities.Runtime.ActivityExecutor.ExecuteInResolutionContextT
   at System.Activities.InArgument`1.TryPopulateValue(LocationEnvironment targetEnvironment, ActivityInstance activityInstance, ActivityExecutor executor)
   at System.Activities.ActivityInstance.InternalTryPopulateArgumentValueOrScheduleExpression(RuntimeArgument argument, Int32 nextArgumentIndex, ActivityExecutor executor, IDictionary`2 argumentValueOverrides, Location resultLocation, Boolean isDynamicUpdate)
   at System.Activities.ActivityInstance.ResolveArguments(ActivityExecutor executor, IDictionary`2 argumentValueOverrides, Location resultLocation, Int32 startIndex)
   at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

更新 2:该过程似乎仍有问题,但频率较低。这是今天早上发生的非致命错误的示例:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (3540): Could not copy "C:\Builds19\Policy Tracker\Container Build\src\Stage\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll" to "C:\Builds19\Policy Tracker\Container Build\bin\Microsoft.Owin.Security.Cookies.dll". Beginning retry 1 in 1000ms. The process cannot access the file 'C:\Builds19\Policy Tracker\Container Build\bin\Microsoft.Owin.Security.Cookies.dll' because it is being used by another process.

我目前正在调查 http://blogs.msdn.com/b/visualstudio/archive/2010/12/21/incorrect-solution-build-ordering-when-using-msbuild-exe.aspx 作为问题的可能来源(不正确的解决方案排序)。这适用于以前的版本,但症状看起来非常相似。

我已经通过构建服务器中的设置解决了这个问题:Process 选项卡上的 MSBuild Multi-Proc。我将此设置为 True (默认值),并且得到了问题中提到的随机错误。将其翻转为 False 允许几天的签入代码构建、测试和部署完全按照产品的预期工作。

我的研究指出 MSBuild 和 Visual Studio 扫描项目依赖项的方法之间存在差异,但我还没有找到解决方案文件中的这些差异的方法,我正在尝试尽可能保持简单。切换到单进程构建已将构建时间从 3 分钟增加到 6 分钟,但我发现在面临非确定性和确定性结果之间的选择时,这是一个可以接受的损失。