@@ -104,6 +104,15 @@ internal class OutOfProcTaskHostNode :
104104 /// </summary>
105105 private string _forwardSolutionConfigBaseline ;
106106
107+ /// <summary>
108+ /// The build process environment whose values are currently reflected in this task host process. Used to
109+ /// skip the redundant per-task environment apply + restore when the next task's environment is identical
110+ /// and the previous task did not mutate it. Set to <see langword="null"/> whenever a task blocks on a
111+ /// callback (<see cref="SaveOperatingEnvironment"/>) or the node is reused for a new build, so nested
112+ /// activity and build boundaries always force a fresh apply.
113+ /// </summary>
114+ private IDictionary < string , string > _lastAppliedConfigEnvironment ;
115+
107116 /// <summary>
108117 /// The event which is set when we should shut down.
109118 /// </summary>
@@ -1137,6 +1146,9 @@ private void SaveOperatingEnvironment(TaskExecutionContext context)
11371146 {
11381147 ArgumentNullException . ThrowIfNull ( context ) ;
11391148
1149+ // A task is about to block and let a nested task run, which may change the process environment.
1150+ _lastAppliedConfigEnvironment = null ;
1151+
11401152 context . SavedCurrentDirectory = Environment . CurrentDirectory ;
11411153 context . SavedEnvironment = new Dictionary < string , string > (
11421154 CommunicationsUtilities . GetEnvironmentVariables ( ) ,
@@ -1312,6 +1324,10 @@ private void HandleNodeBuildComplete(NodeBuildComplete buildComplete)
13121324 {
13131325 Assumed . Zero ( _activeTaskCount , "We should never have a task in the process of executing when we receive NodeBuildComplete." ) ;
13141326
1327+ // When this node is reused for a later build, reset the environment-reuse cache so the first task of
1328+ // the next build performs a fresh apply rather than trusting state left over from this build.
1329+ _lastAppliedConfigEnvironment = null ;
1330+
13151331 // Sidecar TaskHost will persist after the build is done.
13161332 if ( _nodeReuse )
13171333 {
@@ -1476,14 +1492,24 @@ private void RunTask(object state)
14761492 // Change to the startup directory
14771493 NativeMethodsShared . SetCurrentDirectory ( taskConfiguration . StartupDirectory ) ;
14781494
1479- if ( _updateEnvironment )
1495+ bool canSkipEnvironmentApply = _lastAppliedConfigEnvironment is not null
1496+ && _blockedTaskCount == 0
1497+ && _activeTaskCount == 1
1498+ && CommunicationsUtilities . AreEnvironmentsEquivalent ( taskConfiguration . BuildProcessEnvironment , _lastAppliedConfigEnvironment ) ;
1499+
1500+ if ( ! canSkipEnvironmentApply )
14801501 {
1481- InitializeMismatchedEnvironmentTable ( taskConfiguration . BuildProcessEnvironment ) ;
1502+ if ( _updateEnvironment )
1503+ {
1504+ InitializeMismatchedEnvironmentTable ( taskConfiguration . BuildProcessEnvironment ) ;
1505+ }
1506+
1507+ // Now set the new environment
1508+ SetTaskHostEnvironment ( taskConfiguration . BuildProcessEnvironment ) ;
1509+ DotnetHostEnvironmentHelper . ClearBootstrapDotnetRootEnvironment ( taskConfiguration . BuildProcessEnvironment ) ;
14821510 }
14831511
1484- // Now set the new environment
1485- SetTaskHostEnvironment ( taskConfiguration . BuildProcessEnvironment ) ;
1486- DotnetHostEnvironmentHelper . ClearBootstrapDotnetRootEnvironment ( taskConfiguration . BuildProcessEnvironment ) ;
1512+ _lastAppliedConfigEnvironment = taskConfiguration . BuildProcessEnvironment ;
14871513
14881514 // Set culture
14891515 Thread . CurrentThread . CurrentCulture = taskConfiguration . Culture ;
@@ -1567,8 +1593,16 @@ private void RunTask(object state)
15671593 }
15681594#endif
15691595
1570- // Restore the original clean environment
1571- CommunicationsUtilities . SetEnvironment ( _savedEnvironment ) ;
1596+ bool canSkipEnvironmentRestore = environmentUnchangedByTask
1597+ && _blockedTaskCount == 0
1598+ && ReferenceEquals ( _lastAppliedConfigEnvironment , taskConfiguration . BuildProcessEnvironment ) ;
1599+
1600+ if ( ! canSkipEnvironmentRestore )
1601+ {
1602+ // Restore the original clean environment
1603+ CommunicationsUtilities . SetEnvironment ( _savedEnvironment ) ;
1604+ _lastAppliedConfigEnvironment = null ;
1605+ }
15721606 }
15731607 catch ( Exception e )
15741608 {
0 commit comments