Repository navigation
Backport: make DispatcherModelSpec.A_dispatcher_must_process_messages_one_at_a_time deterministic (backport of #8299) - #8300
Merged
Aaronontheweb merged 2 commits intoJul 2, 2026
Conversation
The `A_dispatcher_must_process_messages_one_at_a_time` test in the shared `ActorModelSpec` harness was intermittently flaky under CI. Root cause (test-only race, not a dispatcher bug): The test held the actor "busy" with a hard-coded, NON-dilated `Thread.Sleep(1000)` inside the `Wait` handler, then asserted the second message's countdown against a `Dilated(1.5s)` deadline. That leaves only a ~500ms margin above the fixed 1s sleep. Under ThreadPool starvation on CI the margin is consumed and the legitimate countdown arrives late, producing a false failure. Isolation is never actually violated -- the `_busy` Switch guards it and `Restarts` stays 0. Fix (deterministic, latch-controlled -- mirrors the sibling `A_dispatcher_must_process_messages_in_parallel` `Meet(aStart, aStop)` pattern): - Replace `Wait(1000)` with a test-controlled `Meet(busyStarted, release)` latch so the actor stays busy until the test explicitly releases it, removing the wall-clock race entirely. - While the actor is held busy, send `CountDown(oneAtTime)` and use `AssertNoCountdown(..., 500ms)` to POSITIVELY prove the second message is not processed while busy -- a stronger "one at a time" assertion than inferring it from a restart that never happens. - After releasing the gate, `AssertCountdown(oneAtTime, Dilated(3s))` proves it IS processed once free (matching the 3s the same test already grants the first message). Message accounting is unchanged: the test still sends exactly three messages (CountDown, Meet, CountDown), so the trailing `AssertRefDefaultZero(registers: 1, msgsReceived: 3, msgsProcessed: 3)` counts remain correct. Test-only change. No production code under src/core/Akka/Dispatch/ was modified; the dispatcher/mailbox behavior is correct. (cherry picked from commit 2b1902f)
Aaronontheweb
enabled auto-merge (squash)
July 2, 2026 18:05
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.
This is the v1.5 backport of dev PR #8299 — a test-only stability fix. It is preserved as an individual cherry-pick (
-xprovenance) and is separate from the other in-flight backport PRs (#8296, #8298).The flake
DispatcherModelSpec.A_dispatcher_must_process_messages_one_at_a_time(in the sharedActorModelSpecharness) was intermittently flaky under CI.Root cause (test-only race, not a dispatcher bug): the test held the actor "busy" with a hard-coded, non-dilated
Thread.Sleep(1000)inside theWaithandler, then asserted the second message's countdown against aDilated(1.5s)deadline. That leaves only a ~500ms margin above the fixed 1s sleep. Under ThreadPool starvation on CI the margin is consumed and the legitimate countdown arrives late, producing a false failure. Isolation is never actually violated — the_busySwitch guards it andRestartsstays 0.The fix (deterministic, latch-controlled)
Mirrors the sibling
A_dispatcher_must_process_messages_in_parallelMeet(aStart, aStop)pattern:Wait(1000)with a test-controlledMeet(busyStarted, release)latch so the actor stays busy until the test explicitly releases it — removing the wall-clock race entirely.CountDown(oneAtTime)and useAssertNoCountdown(..., 500ms)to positively prove the second message is not processed while busy — a stronger "one at a time" assertion than inferring it from a restart that never happens.AssertCountdown(oneAtTime, Dilated(3s))proves it is processed once free (matching the 3s the same test already grants the first message).Message accounting is unchanged: the test still sends exactly three messages (
CountDown,Meet,CountDown), so the trailingAssertRefDefaultZero(registers: 1, msgsReceived: 3, msgsProcessed: 3)counts remain correct.Test-only change. No production code under
src/core/Akka/Dispatch/was modified — the dispatcher/mailbox behavior is correct.Local validation (net10.0)
dotnet build src/core/Akka.Tests/Akka.Tests.csproj -c Release -warnaserror→ 0 warnings, 0 errors--filter FullyQualifiedName~process_messages_one_at_a_time) → all 5 passed (1/1 each)DispatcherModelSpecsuite → 8/8 passedCherry-picked cleanly from
2b1902fwith no conflicts / no hand-porting required.