Skip to content

Fix TaskHostTask to pass request-level global properties to TaskHost#13443

Merged
JanProvaznik merged 6 commits intodotnet:mainfrom
JanProvaznik:fix/taskhosttask-global-properties
Mar 27, 2026
Merged

Fix TaskHostTask to pass request-level global properties to TaskHost#13443
JanProvaznik merged 6 commits intodotnet:mainfrom
JanProvaznik:fix/taskhosttask-global-properties

Conversation

@JanProvaznik
Copy link
Copy Markdown
Member

Summary

Fixes #13153 — -mt mode breaks NuGet static graph restore for conditional ProjectReference items that depend on MSBuildRestoreSessionId.

Root Cause

When -mt mode routes tasks to an out-of-process TaskHost (via TaskRouter.NeedsTaskHostInMultiThreadedMode()), TaskHostTask.Execute() was sending BuildParameters.GlobalProperties (build-level) to the TaskHostConfiguration. These build-level properties do not include per-request properties like MSBuildRestoreSessionId that are added by ExecuteRestore() in XMake.cs.

This caused NuGet's RestoreTaskEx (which lacks MSBuildMultiThreadableTaskAttribute and thus gets routed to TaskHost in -mt mode) to receive an empty MSBuildRestoreSessionId via IBuildEngine6.GetGlobalProperties(). The NuGet static graph restore then excluded conditional ProjectReference items, breaking restore for projects like �xternals.csproj in dotnet/runtime.

Without -mt: TaskHost.GetGlobalProperties() returns _requestEntry.RequestConfiguration.GlobalProperties → ✅ includes MSBuildRestoreSessionId

With -mt: OutOfProcTaskHostNode.GetGlobalProperties() returns _currentConfiguration.GlobalProperties (from TaskHostConfiguration) → ❌ only has build-level properties from BuildParameters.GlobalProperties

Fix

New method GetGlobalPropertiesForTaskHost() in TaskHostTask that:

  1. Uses BuildEngine.GetGlobalProperties() via IBuildEngine6 (returns correct request-level properties from RequestConfiguration)
  2. Falls back to BuildParameters.GlobalProperties if IBuildEngine6 is not available
  3. Works on both net10.0 and net472 targets

Validation

  • Built MSBuild (Release, net10.0 + net472) — ✅ compiles clean
  • Built dotnet/runtime with -mt -m -restore using fixed MSBuild
    • externals.csproj correctly restored (was excluded before fix)
    • Binlog confirms: -mt in command line, MSBuildRestoreSessionId set with GUID, RestoreUseStaticGraphEvaluation=true, RestoreTaskEx executed

When -mt mode routes tasks to an out-of-process TaskHost, the
TaskHostTask was sending BuildParameters.GlobalProperties (build-level)
to the TaskHostConfiguration. These build-level properties do not
include per-request properties like MSBuildRestoreSessionId that are
added by ExecuteRestore().

This caused NuGet's RestoreTaskEx (which lacks
MSBuildMultiThreadableTaskAttribute and thus gets routed to TaskHost
in -mt mode) to receive empty MSBuildRestoreSessionId via
IBuildEngine6.GetGlobalProperties(). The NuGet static graph restore
then excluded conditional ProjectReference items that depend on
MSBuildRestoreSessionId, breaking restore for projects like
externals.csproj in dotnet/runtime.

The fix uses BuildEngine.GetGlobalProperties() (which returns the
correct request-level properties from RequestConfiguration) instead
of BuildParameters.GlobalProperties, with a fallback to the old
behavior if IBuildEngine6 is not available.

Fixes dotnet#13153

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member Author

@JanProvaznik JanProvaznik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

24-Dimension MSBuild Code Review

Verdict: COMMENT — approve after addressing test coverage; comparer fix is nice-to-have.

The fix is well-targeted and correct. TaskHostTask.Execute() was sending build-level BuildParameters.GlobalProperties instead of request-level properties from RequestConfiguration, causing MSBuildRestoreSessionId to be missing in -mt mode.

Findings

Severity Finding
🔴 MAJOR No regression test for MT + request-level global properties scenario
🟠 MODERATE Fallback path (line 437) uses case-sensitive comparer instead of OrdinalIgnoreCase
🟡 NIT Silent fallback should log a diagnostic message

24-Dimension Checklist

All 24 dimensions pass except:

  • Test Coverage (🔴) — No test for the fixed scenario
  • String Comparison (🟠) — Fallback comparer inconsistency
  • Logging (🟡) — Silent fallback

See inline comments for details.

@JanProvaznik JanProvaznik force-pushed the fix/taskhosttask-global-properties branch from 16a88e8 to 36a130e Compare March 24, 2026 11:25
- Gate the fix behind ChangeWave 18.6 so users can opt out via
  MSBUILDDISABLEFEATURESFROMVERSION=18.6 to get the old behavior
  (build-level BuildParameters.GlobalProperties) exactly as before
- Remove dead IBuildEngine6 fallback path — BuildEngine is always a
  TaskHost implementing IBuildEngine6 in this context
- Add GetGlobalPropertiesTask helper and two regression tests:
  - GlobalProperties_ForwardedToAutoEjectedTaskInMultiThreadedMode
    verifies request-level properties reach auto-ejected tasks (dotnet#13153)
  - GlobalProperties_UseBuildLevelWhenChangeWaveDisabled verifies
    the old behavior is preserved when the wave is opted out
- Document the change in ChangeWaves.md under 18.6

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JanProvaznik JanProvaznik force-pushed the fix/taskhosttask-global-properties branch from 36a130e to 20c08c1 Compare March 24, 2026 11:52
JanProvaznik and others added 2 commits March 24, 2026 12:55
- Gate the fix behind ChangeWave 18.6 so users can opt out via
  MSBUILDDISABLEFEATURESFROMVERSION=18.6 to get the old behavior
  (build-level BuildParameters.GlobalProperties) exactly as before
- Remove dead IBuildEngine6 fallback path — BuildEngine is always a
  TaskHost implementing IBuildEngine6 in this context
- Add GetGlobalPropertiesTask helper and two regression tests:
  - GlobalProperties_ForwardedToAutoEjectedTaskInMultiThreadedMode
    verifies request-level properties reach auto-ejected tasks (dotnet#13153)
  - GlobalProperties_UseBuildLevelWhenChangeWaveDisabled verifies
    the old behavior is preserved when the wave is opted out
- Document the change in ChangeWaves.md under 18.6

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JanProvaznik
Copy link
Copy Markdown
Member Author

JanProvaznik commented Mar 24, 2026

validation on runtime running https://dev.azure.com/dnceng-public/public/_build?definitionId=334
runtime passed (in first run, though both failed overall on a race condition that's fixed in main but this branch started too early)

@JanProvaznik JanProvaznik marked this pull request as ready for review March 24, 2026 16:52
Copilot AI review requested due to automatic review settings March 24, 2026 16:52
@JanProvaznik JanProvaznik force-pushed the fix/taskhosttask-global-properties branch from 120070c to cccae85 Compare March 24, 2026 16:55
With the TaskHostTask fix, runtime builds successfully with -mt mode.
Remove it from MSBuildMTExcludedReposOverride so VMR validation
exercises runtime with -mt enabled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JanProvaznik JanProvaznik force-pushed the fix/taskhosttask-global-properties branch from cccae85 to e3ab1b4 Compare March 24, 2026 17:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@JanProvaznik JanProvaznik self-assigned this Mar 25, 2026
Copy link
Copy Markdown
Member

@AR-May AR-May left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I’d like to double‑check with @rainersigwald in case there are any hidden issues with fixing this behavior.

Copy link
Copy Markdown
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I'd like to understand: how did this not break the MSBuild repo? we use static graph restore

@JanProvaznik
Copy link
Copy Markdown
Member Author

It didn't break other stuff such as msbuild because it does not use this pattern:

@JanProvaznik JanProvaznik merged commit 5065de5 into dotnet:main Mar 27, 2026
10 checks passed
dfederm pushed a commit to dfederm/msbuild that referenced this pull request Apr 9, 2026
…otnet#13443)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

validate -mt works with static graph restore

4 participants