Add App Host Support for MSBuild#13175
Merged
YuliiaKovalova merged 60 commits intomainfrom Mar 3, 2026
Merged
Conversation
Member
Author
|
@copilot could you please move all $(LatestDotNetCoreForMSBuild) related changes to a separate PR? |
Contributor
|
@YuliiaKovalova I've opened a new pull request, #13189, to work on those changes. Once the pull request is ready, I'll request review from you. |
90e06c7 to
95f4da2
Compare
kasperk81
reviewed
Feb 4, 2026
…otnet/msbuild into dev/ykovalova/app_host_support
YuliiaKovalova
commented
Feb 4, 2026
YuliiaKovalova
commented
Feb 6, 2026
rainersigwald
added a commit
that referenced
this pull request
Mar 11, 2026
There was a collision between #13220 (at end of build, look for other running MSBuild processes and decide whether node reuse is likely to be worthwhile) and #13175 (use an apphost on core). This broke the overprovisioning detection, which was looking for `dotnet` instead of the new `MSBuild`. Always search for `MSBuild` instead, and remove the now-unnecesary "try to filter `dotnet.exe` processes to those running `MSBuild.dll` code too.
jonathanpeppers
added a commit
to dotnet/android
that referenced
this pull request
Mar 16, 2026
MSBuild 18+ (dotnet/msbuild#13175) added app host support which changes how TaskHostFactory with Runtime="NET" resolves the MSBuild executable. When running from a local/xcopy SDK (bin/Release/dotnet), the task host resolution falls back to the global SDK path because DOTNET_HOST_PATH is not set, causing MSB4216. Set DOTNET_HOST_PATH to so the .NET 11 MSBuild task host can find the correct dotnet host. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
added a commit
to dotnet/android
that referenced
this pull request
Mar 16, 2026
MSBuild 18+ (dotnet/msbuild#13175) added app host support that changed how TaskHostFactory with Runtime="NET" spawns task host processes. The MetadataLoadContext used to inspect task assemblies is disposed before output validation completes, causing MSB4027/MSB4216 on macOS and Linux when running from a local/xcopy SDK. Remove TaskHostFactory and Runtime="NET" from the git prep task UsingTask declarations in XAVersionInfo.targets. These tasks only shell out to git and don't need out-of-proc isolation. Also revert the DOTNET_HOST_PATH workaround attempts in DotNet.targets and msbuild.mk which were insufficient (the issue is MetadataLoadContext lifecycle, not host path resolution). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
added a commit
to dotnet/android
that referenced
this pull request
Mar 16, 2026
The new MSBuild app host (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to bootstrap the .NET runtime when spawning out-of-proc task hosts. Without this, tasks using TaskHostFactory (like ILLink's ComputeManagedAssemblies) fail with MSB4221 when using a locally-installed SDK. Set DOTNET_HOST_PATH in: - msbuild.mk: for all Makefile-driven builds - DotNetCLI.cs: for test-driven dotnet invocations [build] Remove unnecessary DOTNET_HOST_PATH from msbuild.mk The git prep tasks no longer use TaskHostFactory, so the Makefile doesn't need DOTNET_HOST_PATH. Only the test infrastructure needs it for ILLink's TaskHostFactory. [tests] Add comment explaining DOTNET_HOST_PATH workaround Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
added a commit
to dotnet/android
that referenced
this pull request
Mar 17, 2026
Changes: dotnet/dotnet@ee56b9a...5ff448a - **Dependency Updates**: - From [11.0.0-preview.3.26157.103 to 11.0.0-preview.3.26165.107][1] - Microsoft.NET.Workload.Mono.ToolChain.Current.Manifest-11.0.100-preview.3 - Microsoft.NET.ILLink - Microsoft.NETCore.App.Ref - From [11.0.0-beta.26157.103 to 11.0.0-beta.26165.107][1] - Microsoft.DotNet.Build.Tasks.Feed - From [0.11.5-preview.26157.103 to 0.11.5-preview.26165.107][1] - Microsoft.DotNet.Cecil - From [11.0.100-preview.3.26157.103 to 11.0.100-preview.3.26165.107][1] - Microsoft.NET.Sdk - Microsoft.NET.Workload.Emscripten.Current.Manifest-11.0.100-preview.3 - Microsoft.TemplateEngine.Authoring.Tasks [1]: dotnet/dotnet@ee56b9a...5ff448a * [build] Remove TaskHostFactory from XAVersionInfo.targets MSBuild 18+ (dotnet/msbuild#13175) added app host support that changed how TaskHostFactory with Runtime="NET" spawns task host processes. The MetadataLoadContext used to inspect task assemblies is disposed before output validation completes, causing MSB4027/MSB4216 on macOS and Linux when running from a local/xcopy SDK. Remove TaskHostFactory and Runtime="NET" from the git prep task UsingTask declarations in XAVersionInfo.targets. These tasks only shell out to git and don't need out-of-proc isolation. * [build] Set DOTNET_HOST_PATH for MSBuild TaskHostFactory app host The new MSBuild app host (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to bootstrap the .NET runtime when spawning out-of-proc task hosts. Without this, tasks using TaskHostFactory (like ILLink's ComputeManagedAssemblies) fail with MSB4221 when using a locally-installed SDK. Set DOTNET_HOST_PATH in: - DotNetCLI.cs: for test-driven dotnet invocations Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
jonathanpeppers
added a commit
to dotnet/android
that referenced
this pull request
Mar 17, 2026
The new MSBuild app host (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to bootstrap the .NET runtime when spawning out-of-proc task hosts. Without this, tasks using TaskHostFactory (like ILLink's ComputeManagedAssemblies) fail with MSB4221 when using a locally-installed SDK. Backport of the fix from main (287f27d). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
to dotnet/sdk
that referenced
this pull request
Mar 18, 2026
MSBuild's apphost support (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to resolve DOTNET_ROOT when launching out-of-proc task hosts for TaskHostFactory tasks (e.g. ComputeWasmBuildAssets, ComputeManagedAssemblies). The MSBuild apphost is now created in the SDK layout (dotnet/dotnet#5183), so ResolveAppHostOrFallback takes the apphost code path. It calls CreateDotnetRootEnvironmentOverrides which derives DOTNET_ROOT from DOTNET_HOST_PATH. While the dotnet CLI sets this internally, explicitly providing it in the test environment ensures it is available for the task host subprocess launch. Also enable MSBUILDDEBUGCOMM tracing to capture handshake details for diagnosing any remaining task host connection issues. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
to dotnet/sdk
that referenced
this pull request
Mar 18, 2026
MSBuild's apphost support (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to resolve DOTNET_ROOT when launching out-of-proc task hosts for TaskHostFactory tasks (e.g. ComputeWasmBuildAssets, ComputeManagedAssemblies). The MSBuild apphost is now created in the SDK layout (dotnet/dotnet#5183), so ResolveAppHostOrFallback takes the apphost code path. It calls CreateDotnetRootEnvironmentOverrides which derives DOTNET_ROOT from DOTNET_HOST_PATH. While the dotnet CLI sets this internally, explicitly providing it in the test environment ensures it is available for the task host subprocess launch. Diagnostics added: - DOTNET_HOST_PATH set in test environment variables - MSBUILDDEBUGCOMM=1 for node communication tracing - MSBuildDebugEngine=1 with MSBUILDDEBUGPATH for trace file output - SDK layout dump in AoT_Publish test to verify MSBuild apphost presence Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
to dotnet/sdk
that referenced
this pull request
Mar 18, 2026
MSBuild's apphost support (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to resolve DOTNET_ROOT when launching out-of-proc task hosts for TaskHostFactory tasks (e.g. ComputeWasmBuildAssets, ComputeManagedAssemblies). Changes: - Set DOTNET_HOST_PATH in test environment variables - Enable MSBUILDDEBUGCOMM=1 and MSBuildDebugEngine=1 for trace file output - Add SDK layout diagnostics to AoT_Publish test: * List MSBuild* files in SDK folder * Check apphost exists and has execute permissions (ls -la) * Attempt to run the apphost with --help to verify it can launch * Dump MSBuild.runtimeconfig.json content * Log DOTNET_HOST_PATH, DOTNET_ROOT, OS, architecture info * Verify dotnet host exists Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
to dotnet/sdk
that referenced
this pull request
Mar 18, 2026
MSBuild's apphost support (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to resolve DOTNET_ROOT when launching out-of-proc task hosts for TaskHostFactory tasks (e.g. ComputeWasmBuildAssets, ComputeManagedAssemblies). Changes: - Set DOTNET_HOST_PATH in test environment variables - Enable MSBUILDDEBUGCOMM=1 and MSBuildDebugEngine=1 for trace file output - Add SDK layout diagnostics to AoT_Publish test: * List MSBuild* files in SDK folder * Check apphost exists and has execute permissions (ls -la) * Attempt to run the apphost with --help to verify it can launch * Dump MSBuild.runtimeconfig.json content * Log DOTNET_HOST_PATH, DOTNET_ROOT, OS, architecture info * Verify dotnet host exists Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 18, 2026
On macOS, /tmp is a symlink to /private/tmp. The parent process constructs the handshake toolsDirectory from the MSBuild property \ which preserves the unresolved /tmp form. The child task host process computes its toolsDirectory from AppContext.BaseDirectory which the .NET runtime resolves to /private/tmp. The different strings produce different hashes in the handshake salt, resulting in mismatched pipe names and the parent being unable to connect to the child task host (MSB4216). This affects all TaskHostFactory tasks (ComputeWasmBuildAssets, ComputeManagedAssemblies, ILLink, etc.) on macOS when the SDK is installed under a symlinked path. The fix calls Path.GetFullPath() on the msbuildAssemblyPath before using it in the handshake and for path construction, ensuring the parent resolves symlinks the same way the child does. Regression introduced in #13175 (Add App Host Support for MSBuild) which changed the .NET task host handshake from using no explicit toolsDirectory (both sides defaulted to MSBuildToolsDirectoryRoot) to passing an explicit toolsDirectory from the MSBuild property value. Fixes dotnet/sdk#53350 (comment) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 18, 2026
…B4216 On macOS, /tmp is a symlink to /private/tmp. PR #13175 changed ResolveAppHostOrFallback to pass an explicit toolsDirectory to the parent's Handshake constructor, sourced from the MSBuild property (NetCoreSdkRoot = MSBuildThisFileDirectory). The child task host process computes its toolsDirectory from AppContext.BaseDirectory via MSBuildToolsDirectoryRoot. On macOS, MSBuild properties preserve the unresolved /tmp form while AppContext.BaseDirectory resolves to /private/tmp. The different strings produce different hashes in the handshake salt, resulting in mismatched pipe names — the parent listens on one pipe, the child connects to another — causing MSB4216. Before #13175, both parent and child used MSBuildToolsDirectoryRoot as the default (no explicit toolsDirectory), so both resolved symlinks identically and the handshake matched. The fix uses BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot for the handshake toolsDirectory on the parent side — the same source the child uses — ensuring path strings match regardless of symlinks. File I/O operations continue to use the original msbuildAssemblyPath (both path forms work for filesystem access on macOS). Fixes dotnet/sdk#53350 (comment) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
added a commit
to dotnet/android
that referenced
this pull request
Mar 18, 2026
Changes: dotnet/dotnet@1e7efac...695853e * Update dependencies from https://github.com/dotnet/dotnet build 20260315.6 On relative base path root Microsoft.DotNet.Build.Tasks.Feed From Version 10.0.0-beta.26156.117 -> To Version 10.0.0-beta.26165.106 Microsoft.NET.Sdk From Version 10.0.300-preview.26156.117 -> To Version 10.0.300-preview.0.26165.106 Microsoft.TemplateEngine.Authoring.Tasks From Version 10.0.300-preview.26156.117 -> To Version 10.0.300-preview.26165.106 * Remove dead DARC NuGet feeds These feeds were added manually for older servicing releases (runtime 9.0.5 and 8.0.16) and have since been cleaned up from Azure DevOps. They cause NU1900 restore failures (warnings-as-errors). * Switch MAUI pipeline ref from net10.0 to main MAUI's net10.0 branch has a dead DARC feed (darc-pub-dotnet-android-1719a35b) that causes NU1301 restore failures. MAUI main targets .NET 10 and does not have the stale feed. * [build] Ignore `RS0016` public API errors in MAUI integration lane (#10884) Set `PublicApiType=Generate` on the `maui_tests_integration` job to skip the `Microsoft.CodeAnalysis.PublicApiAnalyzers` package, which produces `RS0016` errors for new/changed MAUI APIs that dotnet/android does not need to validate. * Set DOTNET_HOST_PATH for MSBuild TaskHostFactory app host The new MSBuild app host (dotnet/msbuild#13175) requires DOTNET_HOST_PATH to bootstrap the .NET runtime when spawning out-of-proc task hosts. Without this, tasks using TaskHostFactory (like ILLink's ComputeManagedAssemblies) fail with MSB4221 when using a locally-installed SDK. Backport of the fix from main (287f27d). Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
YuliiaKovalova
added a commit
to dotnet/sdk
that referenced
this pull request
Mar 18, 2026
The Helix test environment sets DOTNET_ROOT but not DOTNET_HOST_PATH. MSBuild's apphost support (dotnet/msbuild#13175) needs DOTNET_HOST_PATH to derive DOTNET_ROOT when launching TaskHostFactory tasks as out-of-proc MSBuild apphost child processes. Without DOTNET_HOST_PATH, AddNetHostParamsIfNeeded in AssemblyTaskFactory cannot populate DotnetHostPath/MSBuildAssemblyPath, and the task host launch fails with MSB4216. Confirmed via diagnostic run on Helix macOS: DOTNET_HOST_PATH was empty in the test runner process environment while DOTNET_ROOT was set. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 19, 2026
Remove explicit toolsDirectory from Handshake in ResolveAppHostOrFallback. Root cause: On macOS, /tmp is a symlink to /private/tmp. The parent process passed toolsDirectory from $(NetCoreSdkRoot) MSBuild property (which preserves the unresolved symlink path /tmp/...), while the child task host computed its toolsDirectory from BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot (derived from AppContext.BaseDirectory, which resolves symlinks to /private/tmp/...). This produced different handshake hashes, causing the parent to fail to connect to the child task host process with MSB4216. Fix: Don't pass explicit toolsDirectory to the Handshake constructor. Both parent and child now default to BuildEnvironmentHelper, which consistently resolves symlinks via AppContext.BaseDirectory. Before PR #13175, neither side passed explicit toolsDirectory, so both defaulted to BuildEnvironmentHelper and always matched. PR #13175 introduced the asymmetry by passing on the parent side. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 19, 2026
) ### Context PR #13175 (App Host Support) introduced a regression on macOS when the SDK is accessed through a symlinked path. On macOS, `/tmp` is a symlink to `/private/tmp`. When Helix tests run from `/tmp/helix/...`, the `$(NetCoreSdkRoot)` MSBuild property preserves the unresolved path `/tmp/helix/.../sdk/11.0.100-ci`, but the child task host process resolves it to `/private/tmp/helix/.../sdk/11.0.100-ci` via `AppContext.BaseDirectory`. ### Root Cause In `ResolveAppHostOrFallback`, the parent passed `toolsDirectory: msbuildAssemblyPath` (from `$(NetCoreSdkRoot)`) to the `Handshake` constructor, while the child (`NodeEndpointOutOfProcTaskHost`) passed no explicit `toolsDirectory`, defaulting to `BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot` (which resolves symlinks). This produced different handshake hashes: - **Parent**: `hash("/tmp/.../sdk/11.0.100-ci")` - **Child**: `hash("/private/tmp/.../sdk/11.0.100-ci")` - **Result**: Handshake mismatch -> MSB4216 Before PR #13175, neither side passed explicit `toolsDirectory`, so both defaulted to `BuildEnvironmentHelper` and always matched. ### Changes Made - On .NET Core (`#if RUNTIME_TYPE_NETCORE`): omit explicit `toolsDirectory` so both parent and child default to `BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot`, which resolves symlinks consistently via `AppContext.BaseDirectory`. - On .NET Framework: keep `toolsDirectory: msbuildAssemblyPath` because the parent (VS) and child (.NET task host) are in **different directories**, and Windows has no symlink issues. - Updated regression test to validate actual fix behavior (not tautological). ### Testing - `Handshake_ExternalPathCanMismatch_DefaultAlwaysMatches` - proves that an external path (like `$(NetCoreSdkRoot)`) produces a different handshake than the default, and that omitting `toolsDirectory` on both sides always matches. - `Handshake_WithSymlinkedToolsDirectory_ProducesDifferentKey` - proves the bug mechanism with real symlinks on Unix. - Existing E2E tests for TaskHostFactory tasks. - SDK test validation on Helix macOS (the original failing environment). ### Notes This fix addresses the MSB4216 errors seen in SDK Helix tests for `ComputeWasmBuildAssets`, `ComputeManagedAssemblies`, `MarshalingPInvokeScanner`, and other `TaskHostFactory` tasks on macOS. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AR-May
pushed a commit
to AR-May/msbuild
that referenced
this pull request
Mar 19, 2026
…net#13406) ### Context PR dotnet#13175 (App Host Support) introduced a regression on macOS when the SDK is accessed through a symlinked path. On macOS, `/tmp` is a symlink to `/private/tmp`. When Helix tests run from `/tmp/helix/...`, the `$(NetCoreSdkRoot)` MSBuild property preserves the unresolved path `/tmp/helix/.../sdk/11.0.100-ci`, but the child task host process resolves it to `/private/tmp/helix/.../sdk/11.0.100-ci` via `AppContext.BaseDirectory`. ### Root Cause In `ResolveAppHostOrFallback`, the parent passed `toolsDirectory: msbuildAssemblyPath` (from `$(NetCoreSdkRoot)`) to the `Handshake` constructor, while the child (`NodeEndpointOutOfProcTaskHost`) passed no explicit `toolsDirectory`, defaulting to `BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot` (which resolves symlinks). This produced different handshake hashes: - **Parent**: `hash("/tmp/.../sdk/11.0.100-ci")` - **Child**: `hash("/private/tmp/.../sdk/11.0.100-ci")` - **Result**: Handshake mismatch -> MSB4216 Before PR dotnet#13175, neither side passed explicit `toolsDirectory`, so both defaulted to `BuildEnvironmentHelper` and always matched. ### Changes Made - On .NET Core (`#if RUNTIME_TYPE_NETCORE`): omit explicit `toolsDirectory` so both parent and child default to `BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot`, which resolves symlinks consistently via `AppContext.BaseDirectory`. - On .NET Framework: keep `toolsDirectory: msbuildAssemblyPath` because the parent (VS) and child (.NET task host) are in **different directories**, and Windows has no symlink issues. - Updated regression test to validate actual fix behavior (not tautological). ### Testing - `Handshake_ExternalPathCanMismatch_DefaultAlwaysMatches` - proves that an external path (like `$(NetCoreSdkRoot)`) produces a different handshake than the default, and that omitting `toolsDirectory` on both sides always matches. - `Handshake_WithSymlinkedToolsDirectory_ProducesDifferentKey` - proves the bug mechanism with real symlinks on Unix. - Existing E2E tests for TaskHostFactory tasks. - SDK test validation on Helix macOS (the original failing environment). ### Notes This fix addresses the MSB4216 errors seen in SDK Helix tests for `ComputeWasmBuildAssets`, `ComputeManagedAssemblies`, `MarshalingPInvokeScanner`, and other `TaskHostFactory` tasks on macOS. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 27, 2026
When MSBuild is launched via dotnet.exe (e.g. dotnet build, dotnet msbuild), BuildEnvironmentHelper resolves CurrentMSBuildExePath to MSBuild.exe (the AppHost) because it prefers .exe over .dll. This causes all out-of-proc worker nodes to launch as MSBuild.exe AppHost processes, incurring native bootstrap overhead per node. This change detects when the current process is dotnet.exe and the resolved MSBuild location is the AppHost, then substitutes MSBuild.dll so worker nodes are launched via dotnet.exe instead. This only applies to regular worker nodes (nodemode:1), not task host nodes (nodemode:2) which may need the AppHost for COM host object support. Fixes a ~16% regression in NuGet restore of OrchardCore (61s -> 72s) introduced by the AppHost PR #13175.
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 27, 2026
When MSBuild is launched via dotnet.exe (e.g. dotnet build, dotnet msbuild), BuildEnvironmentHelper resolves CurrentMSBuildExePath to MSBuild.exe (the AppHost) because it prefers .exe over .dll. This causes all out-of-proc worker nodes to launch as MSBuild.exe AppHost processes, incurring native bootstrap overhead per node. This change detects when the current process is dotnet.exe and the resolved MSBuild location is the AppHost, then substitutes MSBuild.dll so worker nodes are launched via dotnet.exe instead. This only applies to regular worker nodes (nodemode:1), not task host nodes (nodemode:2) which may need the AppHost for COM host object support. Fixes a ~16% regression in NuGet restore of OrchardCore (61s -> 72s) introduced by the AppHost PR #13175.
YuliiaKovalova
added a commit
that referenced
this pull request
Mar 27, 2026
When MSBuild is launched via dotnet.exe (e.g. dotnet build, dotnet msbuild), BuildEnvironmentHelper resolves CurrentMSBuildExePath to MSBuild.exe (the AppHost) because it prefers .exe over .dll. This causes all out-of-proc worker nodes to launch as MSBuild.exe AppHost processes, incurring native bootstrap overhead per node. This change detects when the current process is dotnet.exe and the resolved MSBuild location is the AppHost, then substitutes MSBuild.dll so worker nodes are launched via dotnet.exe instead. This only applies to regular worker nodes (nodemode:1), not task host nodes (nodemode:2) which may need the AppHost for COM host object support. Fixes a ~16% regression in NuGet restore of OrchardCore (61s -> 72s) introduced by the AppHost PR #13175.
rainersigwald
added a commit
that referenced
this pull request
Mar 30, 2026
Adds ETW instrumentation around the node create-or-connect path in `NodeProviderOutOfProcBase.GetNodes`, to help chase down a possible regression from #13175. ## New ETW events | Event | ID | Parameters | Description | |---|---|---|---| | `NodeConnectStart` | 99 | `nodeId` | Begin acquiring a node (reuse or launch) | | `NodeConnectStop` | 100 | `nodeId`, `processId`, `isReused` | Node acquired successfully | | `NodeReuseScanStart` | 101 | | Begin scanning for reusable node processes | | `NodeReuseScanStop` | 102 | `candidateCount` | Scan complete | | `NodeLaunchStart` | 103 | `nodeId` | Begin OS process creation | | `NodeLaunchStop` | 104 | `nodeId`, `processId` | Process created | | `NodePipeConnectStart` | 105 | `nodeId`, `processId` | Begin named pipe connect + handshake | | `NodePipeConnectStop` | 106 | `nodeId`, `processId`, `success` | Pipe connect complete | ## Timeline (new node) ``` NodeReuseScanStart / NodeReuseScanStop(candidates) NodeConnectStart(nodeId) NodeLaunchStart(nodeId) NodeLaunchStop(nodeId, pid) NodePipeConnectStart(nodeId, pid) NodePipeConnectStop(nodeId, pid, success) NodeConnectStop(nodeId, pid, isReused=false) ``` ## Timeline (reused node) ``` NodeReuseScanStart / NodeReuseScanStop(candidates) NodeConnectStart(nodeId) NodePipeConnectStart(nodeId, candidatePid) NodePipeConnectStop(nodeId, candidatePid, success) NodeConnectStop(nodeId, pid, isReused=true) ``` Both `NodeProviderOutOfProc` and `NodeProviderOutOfProcTaskHost` flow through `GetNodes`. No behavioral change. Pure observability addition. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
rainersigwald
pushed a commit
that referenced
this pull request
Mar 30, 2026
…os (#13452) PR #13175 introduced the MSBuild AppHost (`MSBuild.exe`). After this change, `dotnet build` spawns worker nodes as `MSBuild.exe` processes. ETL trace analysis of OrchardCore NuGet restore shows a **~16% regression** (61s -> 72s): The root cause of the performance difference is not fully understood. Reverting worker nodes to `dotnet MSBuild.dll` in CLI scenarios restores baseline performance.
dfederm
pushed a commit
to dfederm/msbuild
that referenced
this pull request
Apr 9, 2026
Adds ETW instrumentation around the node create-or-connect path in `NodeProviderOutOfProcBase.GetNodes`, to help chase down a possible regression from dotnet#13175. ## New ETW events | Event | ID | Parameters | Description | |---|---|---|---| | `NodeConnectStart` | 99 | `nodeId` | Begin acquiring a node (reuse or launch) | | `NodeConnectStop` | 100 | `nodeId`, `processId`, `isReused` | Node acquired successfully | | `NodeReuseScanStart` | 101 | | Begin scanning for reusable node processes | | `NodeReuseScanStop` | 102 | `candidateCount` | Scan complete | | `NodeLaunchStart` | 103 | `nodeId` | Begin OS process creation | | `NodeLaunchStop` | 104 | `nodeId`, `processId` | Process created | | `NodePipeConnectStart` | 105 | `nodeId`, `processId` | Begin named pipe connect + handshake | | `NodePipeConnectStop` | 106 | `nodeId`, `processId`, `success` | Pipe connect complete | ## Timeline (new node) ``` NodeReuseScanStart / NodeReuseScanStop(candidates) NodeConnectStart(nodeId) NodeLaunchStart(nodeId) NodeLaunchStop(nodeId, pid) NodePipeConnectStart(nodeId, pid) NodePipeConnectStop(nodeId, pid, success) NodeConnectStop(nodeId, pid, isReused=false) ``` ## Timeline (reused node) ``` NodeReuseScanStart / NodeReuseScanStop(candidates) NodeConnectStart(nodeId) NodePipeConnectStart(nodeId, candidatePid) NodePipeConnectStop(nodeId, candidatePid, success) NodeConnectStop(nodeId, pid, isReused=true) ``` Both `NodeProviderOutOfProc` and `NodeProviderOutOfProcTaskHost` flow through `GetNodes`. No behavioral change. Pure observability addition. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dfederm
pushed a commit
to dfederm/msbuild
that referenced
this pull request
Apr 9, 2026
…os (dotnet#13452) PR dotnet#13175 introduced the MSBuild AppHost (`MSBuild.exe`). After this change, `dotnet build` spawns worker nodes as `MSBuild.exe` processes. ETL trace analysis of OrchardCore NuGet restore shows a **~16% regression** (61s -> 72s): The root cause of the performance difference is not fully understood. Reverting worker nodes to `dotnet MSBuild.dll` in CLI scenarios restores baseline performance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 1 of: #12995
Context
This PR implements App Host support for MSBuild, enabling MSBuild to run as a native executable (MSBuild.exe or MSBuild on Unix) instead of dotnet + MSBuild.dll
Changes Made
Added DotnetHostEnvironmentHelper class to manage DOTNET_ROOT environment variables
When MSBuild runs as an app host, child processes (worker nodes and task hosts) need DOTNET_ROOT set to locate the .NET runtime
These variables are cleared after startup so they don't leak to tools executed by child processes
Only clears DOTNET_ROOT variants if they weren't present in the original build process environment
Node Launcher Updates
Updated NodeLauncher to pass environment overrides when launching worker nodes
NodeLaunchData record struct with EnvironmentOverrides support
Implemented BuildEnvironmentBlock for Windows process creation with custom environment
NodeProviderOutOfProc and NodeProviderOutOfProcTaskHost now provide DOTNET_ROOT overrides
Notes
Backward compatible: Falls back to dotnet MSBuild.dll if app host doesn't exist (older SDKs)
Uses ProcessStartInfo.Environment for thread-safe, scoped environment overrides
The SDK can continue using dotnet MSBuild.dll or opt to use the new app host—this is not a forced change