Fix hot reload cancellation race - #11401
Amaury Levé (Evangelink) merged 1 commit into
Conversation
Route cancellation through the synchronized shutdown path so the shutdown flag is set before the waiter is released. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The focused synchronization fix resolves the reported race and is covered by meaningful regression assertions.
Review effort: Balanced
Findings: None
What changed in this PR
Fixes the Hot Reload cancellation race by synchronizing shutdown signaling before releasing the waiter.
Changes:
- Routes cancellation through
RequestShutdown. - Removes competing semaphore cancellation.
- Strengthens regression assertions.
Review coverage
Cancellation ordering, caller behavior, framework compatibility, and regression coverage.| File | Description |
|---|---|
HotReloadHandler.cs |
Serializes cancellation and waiter release. |
HotReloadTests.cs |
Verifies shutdown state and subsequent-run prevention. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
/backport to rel/4.4 |
|
Started backporting to rel/4.4: https://github.com/microsoft/testfx/actions/runs/35593656676 |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch
Patch format detection failed.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
12 similar comments
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
4 similar comments
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Amaury Levé (@Evangelink) backporting to rel/4.4 failed, the patch most likely resulted in conflicts: $ git am --continue
fatal: Resolve operation not in progress, we are not resuming.
Error: The process '/usr/bin/git' failed with exit code 128NOTE: A PR will be created, but needs to be revised manually! |
|
Potential infinite loop guard hit. Stopping |
…o rel/4.4) (#11404) Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Summary
ShouldRunAsynccancellation through the synchronized shutdown path so the shutdown flag is set before the semaphore waiter is released.SemaphoreSlim.WaitAsynccancellation callback that could resume the waiter before the shutdown callback ran.The flaky failure was observed in #11387 on Linux/net9.0. The failure exposed a real callback-ordering race; this change does not assume how frequently that ordering occurs.
Validation
.\build.cmd -projects test\UnitTests\Microsoft.Testing.Extensions.UnitTests\Microsoft.Testing.Extensions.UnitTests.csproj -bl(0 warnings, 0 errors; MSBuild binlog generated).\.dotnet\dotnet.exe run --project test\UnitTests\Microsoft.Testing.Extensions.UnitTests\Microsoft.Testing.Extensions.UnitTests.csproj -f net9.0 --no-build -c Debug -bl:artifacts\log\Debug\HotReloadFixTest.binlog -- --filter "FullyQualifiedName=Microsoft.Testing.Extensions.UnitTests.HotReloadTests.ShouldRunAsync_WaiterIsBlockedAndCancellationIsRequested_StopsNextRun" --minimum-expected-tests 1(1 passed)