Repository navigation
Fix headless session startup and disposal races - #22222
Merged
MrJul merged 3 commits intoSep 15, 2026
Merged
Conversation
|
You can test this PR using the following package version. |
Collaborator
|
Contributor
Author
|
@cla-avalonia agree |
MrJul
approved these changes
Sep 15, 2026
MrJul
left a comment
Member
There was a problem hiding this comment.
Tested, works as expected. LGTM!
MrJul
added a commit
to MrJul/Avalonia
that referenced
this pull request
Sep 22, 2026
* Test immediate synchronous and asynchronous headless session disposal * Initialize headless dispatch task before starting and stop it before queue completion --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
countincognito
added a commit
to countincognito/Zametek.ProjectPlan
that referenced
this pull request
Sep 26, 2026
…hine. Now and then the Graphs suite failed on Linux with every test passing: xUnit reported a cleanup failure of the "Headless rendering" collection, a NullReferenceException thrown from HeadlessUnitTestSession.Dispose. Avalonia 12.1.1's StartNew hands the new session its dispatch task through a variable that the dispatch thread can read before StartNew has assigned it. When that thread gets there first, the session holds no task, and Dispose throws where it waits for it, after it has already stopped the dispatch loop. It takes a busy machine, and CI no longer tolerates a failing test step, so it would have failed CI at random. The fixture now tolerates exactly that state, which it recognises by reading the session's private _dispatchTask, so any other failure to dispose still fails the run. Avalonia fixed the race in 12.1.3 (AvaloniaUI/Avalonia#22222), and TODO.md records moving to it and deleting the guard. Under WSL, with both cores kept busy and two suites running at a time, 5 of 30 runs failed, each of them a session started without its task. With the guard, 30 of 30 passed although 7 sessions started without their task, and 20 of 20 passed on the fixture as committed. Windows never hit the race in 30 runs under the same kind of load, and all suites pass there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
countincognito
added a commit
to countincognito/Zametek.ProjectPlan
that referenced
this pull request
Sep 26, 2026
… headless session guard it replaces. Avalonia 12.1.3 fixes the race in HeadlessUnitTestSession.StartNew (AvaloniaUI/Avalonia#22222) that ceb80d1 guarded against in the Graphs tests' fixture, so the guard, its comment and its TODO.md entry go. Every Avalonia package moves to 12.1.3 together, with Avalonia.Controls.DataGrid and ReactiveUI.Avalonia at 12.1.2, Dock at 12.1.0.6 and Xaml.Behaviors at 12.0.7, and alongside them Autofac 9.3.4, the Microsoft.Extensions and System packages at 10.0.12, MPXJ.Net 16.9.0, Microsoft.NET.Test.Sdk 18.10.1 and the Windows SDK build tools 10.0.28000.2705. Svg.Skia stays at 5.1.1 and Svg.Controls.Skia.Avalonia at 12.0.0.13, with a comment on each saying why. From Svg.Skia 5.2.0 and Svg.Controls.Skia.Avalonia 12.0.0.14 on, they require SkiaSharp 4.148, which NuGet then resolves for the whole solution, although Avalonia and ScottPlot are still built against SkiaSharp 3.119 and the native libraries pinned for Linux and the browser stay at 3.119.4. On Linux every draw failed, SkiaSharp refusing the version 119 native library in 27 Graphs tests, and the build gained 11 obsolete-API warnings. Under the same CPU load that made the race hit 5 to 7 times in 30 runs of the Graphs suite on 12.1.1, the unguarded fixture now passes 30 of 30, every session starting with its dispatch task. All suites pass on Windows and on Linux with no new warnings, the desktop app was smoke-tested, and zpp's outputs are unchanged: 247 of 250 came out byte-identical, and the three MS Project imports differ only in the day they were run on. Dock.Model.ReactiveUI 12.1.0.6 and DynamicData 9.4.33 still depend on System.Reactive, so it stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
grokys
pushed a commit
to Evan260/Avalonia
that referenced
this pull request
Oct 7, 2026
* Test immediate synchronous and asynchronous headless session disposal * Initialize headless dispatch task before starting and stop it before queue completion --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
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.
What does the pull request do?
Fix two races when immediately disposing a headless test session. The worker can capture its own task before StartNew assigns it, causing a NullReferenceException during disposal. Completing the work queue before the worker exits can also cause BlockingCollection.Take to throw.
Create the worker task before starting it, and wait for it to exit before completing the queue in both disposal methods. No public API changes.
Validation
The first commit adds repeated immediate-disposal tests for synchronous and asynchronous shutdown. Both failed against the baseline; the second commit fixes them. Full NUnit per-test and per-assembly headless suites each passed 85 tests with one skipped; both xUnit suites each passed 80 tests with one skipped. A separate read-only review found no actionable defects.
This change was prepared with AI assistance.