Repository navigation
De-flake ReceiveTimeoutSpec: measure the two timeout cycles with dilated probe waits instead of one flat latch - #8541
Merged
Conversation
Aaronontheweb
enabled auto-merge (squash)
September 9, 2026 15:06
…ted probe waits instead of one flat latch
The latch built with `new TestLatch(...)` does not dilate with akka.test.timefactor,
and the test parked a pool worker in CountdownEvent.Wait while the scheduler's clock
loop and the mailbox shared the same thread pool. Rewrote the test to await a
TestProbe through three per-phase, dilated ExpectMsgAsync budgets instead of one flat
5s wall, stopping the actor in a finally. The probe sequence ("timeout", "tick",
"timeout") also proves the transparent tick was actually delivered, rather than just
inferring it from a latch count.
Also converts the companion negative-assertion test (no receive-timeout ever set)
from a blocking TestLatch wait to ExpectNoMsgAsync on a probe, so it stops parking a
pool worker for the duration of the wait.
Aaronontheweb
force-pushed
the
fix/receive-timeout-spec-probe
branch
from
September 9, 2026 18:18
3c749c9 to
371c0f8
Compare
Aaronontheweb
added a commit
that referenced
this pull request
Sep 12, 2026
…ted probe waits instead of one flat latch (#8541) The latch built with `new TestLatch(...)` does not dilate with akka.test.timefactor, and the test parked a pool worker in CountdownEvent.Wait while the scheduler's clock loop and the mailbox shared the same thread pool. Rewrote the test to await a TestProbe through three per-phase, dilated ExpectMsgAsync budgets instead of one flat 5s wall, stopping the actor in a finally. The probe sequence ("timeout", "tick", "timeout") also proves the transparent tick was actually delivered, rather than just inferring it from a latch count. Also converts the companion negative-assertion test (no receive-timeout ever set) from a blocking TestLatch wait to ExpectNoMsgAsync on a probe, so it stops parking a pool worker for the duration of the wait. (cherry picked from commit 86e479d)
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 changes
ReceiveTimeoutSpecstops waiting on latches built withnew TestLatch(...)and waits onTestProbes instead. The first commit rewrote the two tests that failed; the second migrates the remaining seven synchronous facts the same way, so no blocking wait is left in the file.An_actor_with_receive_timeout_must_get_timeout_while_receiving_only_NotInfluenceReceiveTimeout_messagesnow awaits three probe messages in order: "timeout", then "tick", then "timeout". Each wait has its own dilated budget: 1 s plus 4 s of slack for a timeout cycle, 1 s for the tick, which is a local self-send. It also now proves the transparent tick was delivered between the two timeouts, which the old latch could not.An_actor_with_receive_timeout_must_not_receive_timeout_message_when_not_specifiednow asserts withExpectNoMsgAsyncinstead of catching aTimeoutExceptionfrom a blocking 5 s latch wait.Why
The first test failed on CI build 131165 after exactly 5 s. The product is correct: a message marked
INotInfluenceReceiveTimeoutcannot cancel or re-arm the pending timer, and the code matches Pekko line for line. Two things in the test made it fragile:new TestLatch(n)never dilates its timeout, unlike one built withCreateTestLatch(), so its 5 s wall ignoresakka.test.timefactor. The earlier fix in Fix flaky ReceiveTimeoutSpec CI timeout #8153 helped the sibling test that uses the helper and could not help this one. About 83 call sites in the repo build latches this way.Akka.Testsdisables parallelization. On a 2-vCPU agent one worker ran everything, and any stall landed on the timer. Because the receive timeout is re-armed after the handler returns, lateness in the first cycle was added to the second.Second commit: the remaining facts
The three test actors take a probe instead of a latch and send "timeout" when the receive timeout fires. The seven remaining facts become async and await the probe with the same budget the latch had, or a receive-timeout plus 4 s where the fact measures a 1 s cycle, as the first commit does. The turn-off fact asserts with
ExpectNoMsgAsyncinstead of catching aTimeoutExceptionfrom a 1 s latch wait. The issue-469 fact keeps its probe apart from the test actor so the dead-letter check stays separate. A grep for synchronous TestKit calls andReady(on the file returns nothing. The class run three times: 10 of 10 each time.How it was checked
dotnet build src/core/Akka.Tests -c Release -warnaserrorclean. The rewritten test run 25 times in a row: 25 passes, about 2 s each. The wholeReceiveTimeoutSpecclass: 10 passed.