Skip to content

Commit 164abd4

Browse files
[vs17.14] Add check for node shut down event and reorder the sequence of shutdown in OutOfProcNode (#12235)
1 parent a338add commit 164abd4

File tree

13 files changed

+100
-10
lines changed

13 files changed

+100
-10
lines changed

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the MIT license. See License.txt in the project root for full license information. -->
33
<Project>
44
<PropertyGroup>
5-
<VersionPrefix>17.14.18</VersionPrefix><DotNetFinalVersionKind>release</DotNetFinalVersionKind>
5+
<VersionPrefix>17.14.19</VersionPrefix><DotNetFinalVersionKind>release</DotNetFinalVersionKind>
66
<PackageValidationBaselineVersion>17.13.9</PackageValidationBaselineVersion>
77
<AssemblyVersion>15.1.0.0</AssemblyVersion>
88
<PreReleaseVersionLabel>servicing</PreReleaseVersionLabel>

src/Build.UnitTests/BackEnd/MockSdkResolverService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ internal sealed class MockSdkResolverService : IBuildComponent, ISdkResolverServ
1616
{
1717
public Action<INodePacket> SendPacket { get; }
1818

19+
public bool IsNodeShutDown { get; set; }
20+
1921
public void ClearCache(int submissionId)
2022
{
2123
}
@@ -33,8 +35,6 @@ public void InitializeComponent(IBuildComponentHost host)
3335
{
3436
}
3537

36-
public void ShutdownComponent()
37-
{
38-
}
38+
public void ShutdownComponent() => IsNodeShutDown = true;
3939
}
4040
}

src/Build/BackEnd/BuildManager/BuildManager.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ private static void AttachDebugger()
779779
/// </summary>
780780
public void CancelAllSubmissions()
781781
{
782+
MSBuildEventSource.Log.CancelSubmissionsStart();
782783
CancelAllSubmissions(true);
783784
}
784785

src/Build/BackEnd/Components/Communications/SerializationContractInitializer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ private static void RegisterExceptions()
2525
BuildExceptionSerializationHelper.InitializeSerializationContract(
2626
new(typeof(GenericBuildTransferredException), (msg, inner) => new GenericBuildTransferredException(msg, inner)),
2727
new(typeof(SdkResolverException), (msg, inner) => new SdkResolverException(msg, inner)),
28+
new(typeof(SdkResolverServiceException), (msg, inner) => new SdkResolverServiceException(msg, inner)),
2829
new(typeof(BuildAbortedException), BuildAbortedException.CreateFromRemote),
2930
new(typeof(CircularDependencyException), (msg, inner) => new CircularDependencyException(msg, inner)),
3031
new(typeof(InternalLoggerException), (msg, inner) => new InternalLoggerException(msg, inner)),

src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading;
66
using Microsoft.Build.BackEnd.Logging;
77
using Microsoft.Build.Construction;
8+
using Microsoft.Build.Eventing;
89
using Microsoft.Build.Framework;
910

1011
#nullable disable
@@ -29,6 +30,9 @@ internal abstract class HostedSdkResolverServiceBase : IBuildComponent, INodePac
2930
/// <inheritdoc cref="ISdkResolverService.SendPacket"/>
3031
public Action<INodePacket> SendPacket { get; set; }
3132

33+
/// <inheritdoc cref="ISdkResolverService.IsNodeShutDown"/>
34+
public bool IsNodeShutDown { get; set; }
35+
3236
/// <inheritdoc cref="ISdkResolverService.ClearCache"/>
3337
public virtual void ClearCache(int submissionId)
3438
{
@@ -55,6 +59,8 @@ public virtual void InitializeComponent(IBuildComponentHost host)
5559
public virtual void ShutdownComponent()
5660
{
5761
ShutdownEvent.Set();
62+
IsNodeShutDown = true;
63+
MSBuildEventSource.Log.SdkResolverServiceNodeShutDownSet();
5864
}
5965
}
6066
}

src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ internal interface ISdkResolverService
2020
/// </summary>
2121
Action<INodePacket> SendPacket { get; }
2222

23+
/// <summary>
24+
/// Gets or sets if shutdown event was already triggered.
25+
/// </summary>
26+
bool IsNodeShutDown { get; set; }
27+
2328
/// <summary>
2429
/// Clears the cache for the specified build submission ID.
2530
/// </summary>

src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ public override void PacketReceived(int node, INodePacket packet)
6666
/// <inheritdoc cref="ISdkResolverService.ResolveSdk"/>
6767
public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive, bool isRunningInVisualStudio, bool failOnUnresolvedSdk)
6868
{
69+
if (IsNodeShutDown)
70+
{
71+
throw new SdkResolverServiceException("SDK could not be resolved by the SDK resolver because the worker node was shut down.");
72+
}
73+
6974
bool wasResultCached = true;
7075

7176
MSBuildEventSource.Log.OutOfProcSdkResolverServiceRequestSdkPathFromMainNodeStart(submissionId, sdk.Name, solutionPath, projectPath);
@@ -128,6 +133,11 @@ private SdkResult RequestSdkPathFromMainNode(int submissionId, SdkReference sdk,
128133
// Wait for either the response or a shutdown event. Either event means this thread should return
129134
WaitHandle.WaitAny([_responseReceivedEvent, ShutdownEvent]);
130135

136+
if (_lastResponse == null)
137+
{
138+
throw new SdkResolverServiceException("SDK could not be resolved by the SDK resolver.");
139+
}
140+
131141
// Keep track of the element location of the reference
132142
_lastResponse.ElementLocation = sdkReferenceLocation;
133143

src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public SdkResolverService()
7878
/// <inheritdoc cref="ISdkResolverService.SendPacket"/>
7979
public Action<INodePacket> SendPacket { get; }
8080

81+
/// <inheritdoc cref="ISdkResolverService.IsNodeShutDown"/>
82+
public bool IsNodeShutDown { get; set; }
83+
8184
/// <summary>
8285
/// Determines if the <see cref="SdkReference"/> is the same as the specified version. If the <paramref name="sdk"/> object has <code>null</code> for the version,
8386
/// this method will always return true since <code>null</code> can match any version.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using Microsoft.Build.Framework.BuildException;
6+
7+
#nullable disable
8+
9+
namespace Microsoft.Build.BackEnd.SdkResolution
10+
{
11+
/// <summary>
12+
/// Represents an exception that occurs when an SdkResolverService throws an unhandled exception.
13+
/// </summary>
14+
public class SdkResolverServiceException : BuildExceptionBase
15+
{
16+
public SdkResolverServiceException(string message, params string[] args)
17+
: base(string.Format(message, args))
18+
{
19+
}
20+
21+
// Do not remove - used by BuildExceptionSerializationHelper
22+
internal SdkResolverServiceException(string message, Exception inner)
23+
: base(message, inner)
24+
{ }
25+
}
26+
}

src/Build/BackEnd/Node/OutOfProcNode.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.Build.BackEnd.Logging;
1515
using Microsoft.Build.BackEnd.SdkResolution;
1616
using Microsoft.Build.Evaluation;
17+
using Microsoft.Build.Eventing;
1718
using Microsoft.Build.FileAccesses;
1819
using Microsoft.Build.Framework;
1920
using Microsoft.Build.Internal;
@@ -444,6 +445,14 @@ private NodeEngineShutdownReason HandleShutdown(out Exception exception)
444445
{
445446
CommunicationsUtilities.Trace("Shutting down with reason: {0}, and exception: {1}.", _shutdownReason, _shutdownException);
446447

448+
MSBuildEventSource.Log.OutOfProcNodeShutDownStart();
449+
450+
// Signal the SDK resolver service to shutdown
451+
// It should be shut down first so all the requests for SDK resolution are discarded.
452+
// Otherwise worker node might stuck in a situation where _buildRequestEngine.CleanupForBuild() waiting for the SDK resolver service response from the main node
453+
// and it never comes since we don't listen to _packetReceivedEvent in the middle of the _shutdownEvent.
454+
((IBuildComponent)_sdkResolverService).ShutdownComponent();
455+
447456
// Clean up the engine
448457
if (_buildRequestEngine != null && _buildRequestEngine.Status != BuildRequestEngineStatus.Uninitialized)
449458
{
@@ -455,9 +464,6 @@ private NodeEngineShutdownReason HandleShutdown(out Exception exception)
455464
}
456465
}
457466

458-
// Signal the SDK resolver service to shutdown
459-
((IBuildComponent)_sdkResolverService).ShutdownComponent();
460-
461467
// Dispose of any build registered objects
462468
IRegisteredTaskObjectCache objectCache = (IRegisteredTaskObjectCache)(_componentFactories.GetComponent(BuildComponentType.RegisteredTaskObjectCache));
463469
objectCache.DisposeCacheObjects(RegisteredTaskObjectLifetime.Build);

0 commit comments

Comments
 (0)