[dotnet watch] Make application of changes always async#52469
Merged
tmat merged 3 commits intodotnet:release/10.0.3xxfrom Jan 29, 2026
Merged
[dotnet watch] Make application of changes always async#52469tmat merged 3 commits intodotnet:release/10.0.3xxfrom
tmat merged 3 commits intodotnet:release/10.0.3xxfrom
Conversation
Member
Author
|
@DustinCampbell ptal |
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request refactors the hot reload change application mechanism to always be asynchronous, eliminating the distinction between suspended and non-suspended process states. Previously, the code had two paths: waiting synchronously for changes when the process wasn't suspended, or queueing updates asynchronously when it was suspended (at a breakpoint). This distinction required debugger APIs only available in Visual Studio. The new approach always queues updates asynchronously and reports results through fire-and-forget tasks that complete when operations finish.
Changes:
- Replaced synchronous apply operations with async fire-and-forget pattern that reports completion via task continuations
- Removed
ApplyStatusenum and replaced return values withTask<Task<bool>>to support async completion tracking - Eliminated
isProcessSuspendedparameter from apply methods, simplifying the API - Updated message descriptors to reflect async timing (e.g., "C# and Razor changes applied in Xms" instead of per-project success messages)
- Fixed process exit code handling for Unix signals (SIGKILL tracking)
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/BuiltInTools/HotReloadClient/ApplyStatus.cs | Removed enum entirely as return type changed to bool |
| src/BuiltInTools/HotReloadClient/HotReloadClient.cs | Changed apply methods to return Task<Task<bool>> and added QueueUpdateBatch helper |
| src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs | Refactored to use async queuing pattern with local completion tasks |
| src/BuiltInTools/HotReloadClient/Web/WebAssemblyHotReloadClient.cs | Updated to use new async queuing pattern |
| src/BuiltInTools/HotReloadClient/HotReloadClients.cs | Changed aggregation logic to work with async completion tasks |
| src/BuiltInTools/HotReloadClient/Utilities/ResponseFunc.cs | Changed from Action to Func to return results |
| src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs | Updated to return nullable response results |
| src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs | Added generic result type support |
| src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs | Updated log events for batch-based operations |
| src/BuiltInTools/Watch/HotReload/CompilationHandler.cs | Implemented fire-and-forget pattern for apply operations with stopwatch timing |
| src/BuiltInTools/Watch/HotReload/HotReloadDotNetWatcher.cs | Removed synchronous change handled logging, passes stopwatch to handlers |
| src/BuiltInTools/Watch/Process/RunningProject.cs | Added CompleteApplyOperationAsync to wrap and handle apply task exceptions |
| src/BuiltInTools/Watch/Process/ProcessRunner.cs | Enhanced signal tracking for Unix SIGKILL and Windows Ctrl+C |
| src/BuiltInTools/Watch/Context/EnvironmentOptions.cs | Removed isHotReloadEnabled parameter from timeout method |
| src/BuiltInTools/dotnet-watch/Watch/StaticFileHandler.cs | Added stopwatch for timing static asset changes |
| src/BuiltInTools/dotnet-watch/Program.cs | Simplified process runner initialization |
| src/BuiltInTools/Watch.Aspire/DotNetWatchLauncher.cs | Simplified process runner initialization |
| src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj | Added reference to ResponseFunc utility |
| src/BuiltInTools/Watch/UI/IReporter.cs | Updated message descriptors for async operations |
| test/dotnet-watch.Tests/TestUtilities/TestOptions.cs | Changed timeout to nullable |
| test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs | Updated tests to use new message descriptors |
| test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs | Updated tests to use new message descriptors and removed per-project assertions |
| test/dotnet-watch.Tests/Browser/BrowserTests.cs | Updated test to use new message descriptor |
| test/Microsoft.Extensions.DotNetDeltaApplier.Tests/HotReloadClientTests.cs | Removed suspended/non-suspended test distinction, updated to await async completion |
| test/Microsoft.TemplateEngine.Cli.UnitTests/ParserTests/InstallTests.cs | Removed trailing whitespace |
DustinCampbell
approved these changes
Jan 29, 2026
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.
Application of changes has two code paths. When the process is suspended at a breakpoint we can't wait until the changes are applied in the process because the agent in the process can't execute until the process is resumed by the debugger. In that case we queued an update, assume it's succeeded and continue. If the process isn't suspended, we wait until the agent finishes applying the changes.
This distinction requires debugger API that tell us whether or not the process is suspended. This API is currently only available in VS, not in VS Code.
Rather than adding the API to VS Code, it is simpler to avoid synchronous waiting for completion of the apply operation altogether.
All we need to do on the code path that applies changes is to hook up task completions at various stages that aggregate and report results when apply operations complete.