Repository navigation
Add regression test for reading the file-app sentinel while a writer holds it open - #21456
David Fowler (davidfowl) wants to merge 3 commits into
Conversation
…writing The FileAppRebuildCommandBuildsEditedSourceAndRestartsResource polls now go through ReadSentinelWrittenByRunningProcess, which keeps the current File.ReadAllText behavior. The new test holds the sentinel open the way File.WriteAllText does and is expected to fail on Windows until the reader is fixed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 21456Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 21456" |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
🔵 Needs a closer look
The draft contains only a regression test, while the sharing-safe reader implementation and Windows before/after validation remain pending.
No open issues 🎉
What changed in this PR
This draft adds regression coverage for the Windows sentinel-file sharing violation reported in #20912. The current changes prepare a “before” run; the fix is not yet included.
Changes:
- Extracts sentinel reads into a helper used by both rebuild polling checks, preserving existing read behavior.
- Adds a test that reads the sentinel while a writer remains open and verifies missing-file handling.
| File | Description |
|---|---|
| tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildCoordinatorTests.cs | Extracts sentinel reading and adds concurrent-writer regression coverage. |
Review effort: Balanced
File.ReadAllText opens with FileShare.Read, which on Windows conflicts with the running file app's File.WriteAllTextAsync write handle and throws a sharing violation out of the polling predicate. Open the sentinel with FileShare.ReadWrite | FileShare.Delete so polling never collides with the writer; the poll still waits for the exact expected content. Fixes #20912 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
# Conflicts: # tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildCoordinatorTests.cs
Tests selector1 / 100 PR test projects · 0 PR jobs, from 1 changed file. Selected PR test projects (1 / 100)
Selected PR jobs (0)none How these were chosen — grouped by what changed🧪 Job reasonsnone Selection computed for commit |
|
Merged On the new head, 🤖 Posted by AspireAgent (AI Agent) |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Description
Fixes #20912:
DotnetProjectBuildCoordinatorTests.FileAppRebuildCommandBuildsEditedSourceAndRestartsResourceintermittently fails on Windows with:Root cause
The file app under test writes its sentinel with
File.WriteAllTextAsync, which opens the fileFileAccess.Write, FileShare.Read. The test polls the sentinel withFile.ReadAllText, which opensFileAccess.Read, FileShare.Read. That share mode denies any existing writer.On Windows, if the poll opens the file while the app's write handle is open, the open fails with a sharing violation. The exception escapes the
AssertIsTrueRetryAsyncpredicate and fails the test. The reverse ordering can also make the app's own write fail. Linux doesn't enforce these share modes, which is why every failure is on Windows.Fix
The polls go through
ReadSentinelWrittenByRunningProcess, which opens the sentinel withFileShare.ReadWrite | FileShare.Delete, so neither the test nor the app can hit a sharing violation. The polls still wait for the exact expected content ("initial", then "updated"). A partially written read just doesn't match yet.No assertions were weakened, no sleeps or retries were added, and no exceptions are swallowed apart from
FileNotFoundException, which replaces the previousFile.Existscheck. The change is test-only.Regression test
ReadSentinelWrittenByRunningProcessToleratesConcurrentWriter: it holds the sentinel open exactly asFile.WriteAllText(Async)does (FileMode.Create, FileAccess.Write, FileShare.Read) and reads it through the helper. This is deterministic, with no timing involved.Evidence
CI window:
ci.ymlruns created 2026-10-16..2026-10-30 (main push, PR, dispatch), first attempt only, jobHosting.Dotnet (ubuntu-latest|windows-latest).worker-ran.txtsharing violation. All 7 were thrown from the polling predicate: 6 from the initial poll, 1 from the post-rebuild poll.StopAsynctimeouts in other tests (the DCP stop family, tracked separately).Before/after on
windows-latest(this PR):2f10a45c(before)File.ReadAllTextReadSentinelWrittenByRunningProcessToleratesConcurrentWriterthrew the sameIOException ... worker-ran.txt ... being used by another processfromFile.ReadAllText(199/200 passed). jobb319cccc(after)FileShare.ReadWrite | FileShare.DeleteFileAppRebuildCommandBuildsEditedSourceAndRestartsResource. job. Full CI run 41069348773 green on attempt 1.On Linux, both heads pass. Share modes aren't enforced there, which is consistent with 0/508 Linux failures. Locally on Linux after the fix, both tests passed 3/3.
Checklist
🤖 Posted by AspireAgent (AI Agent)