Repository navigation
De-flake two TestKit timing tests (TestFSMRef state timeout, WaitForRadioSilence reset) in Akka.TestKit and Akka.Hosting.TestKit - #8615
Merged
Aaronontheweb merged 2 commits intoSep 23, 2026
Conversation
…e 500 ms cap A_TestFSMRef_must_allow_access_to_internal_state failed in the Akka.Hosting copy with "Block took 00:00:01.82, exceeding 00:00:00.50" on a 2-vCPU Linux agent. The StateTimeout travels scheduler -> mailbox -> ThreadPool-backed dispatcher, and the synchronous Within/AwaitCondition blocked a pool thread while it waited, so a starved agent easily needs more than 500 ms. Both copies (Akka.Hosting.TestKit.Tests and Akka.TestKit.Tests) now await the condition with a Dilated(5s) bound and assert the 80 ms lower bound with a Stopwatch started before SetStateTimeout. Within's clock started after it, so a stall between the two calls could have made the timeout look early.
Aaronontheweb
enabled auto-merge (squash)
September 23, 2026 17:35
…of a 1.5 s margin
WaitForRadioSilenceAsync_should_reset_timer_twice_only returned {1} instead
of {1,2} in the Akka.Hosting copy on a 2-vCPU Windows agent. Message 2 was
sent 1.5 s after message 1 into a 3 s window that message 1 had just opened,
so a 1.5 s oversleep on the test thread pushed it out.
Both copies now send 2 only 400 ms after 1, in a 4 s window, and prove the
reset from the elapsed time: the silence cannot end before max after 2 was
sent, while without a reset it would end about 400 ms sooner. Delays only
lengthen the measured time. Renamed to what it tests; the maxMessages
violation is already covered by WaitForRadioSilenceAsync_should_fail_immediately_with_bad_input.
Aaronontheweb
disabled auto-merge
September 23, 2026 19:27
Aaronontheweb
added a commit
that referenced
this pull request
Oct 3, 2026
* De-flake ActorSystemSpec.Log_dead_letters: await DeadLetterListener startup (#8428) The test intermittently failed with 'Only received 0/1 messages that matched filter [Info when Message contains "not delivered"]' (Azure build 129444, Windows unit lane) — zero matches, not a late one, which no timeout increase would fix. Root cause is a genuine startup race. ActorSystemImpl.Start() creates the listener fire-and-forget (ActorSystemImpl.cs:219 'SystemActorOf<DeadLetterListener>("deadLetterListener")'), and the EventStream subscription itself happens inside DeadLetterListener.PreStart() (DeadLetterListener.cs:40). Unlike the configured akka.loggers, that startup has no synchronous handshake before ActorSystem.Create returns, so a dead letter published in the window before PreStart runs has no subscriber, is dropped, and never produces a 'not delivered' log at all. Resolve /system/deadLetterListener before exercising the dead letter. An actor always processes its Create system message (which runs PreStart) before any user message, so a successful Identify reply is proof the DeadLetter subscription is in place — a real happens-before, not a padded wait. Verified: full ActorSystemSpec green; the dead-letter test 12/12 at 2x core saturation (a non-regression check — the race is too rare to reproduce locally on demand). (cherry picked from commit d5993ab) * De-flake two TestKit timing tests (TestFSMRef state timeout, WaitForRadioSilence reset) in Akka.TestKit and Akka.Hosting.TestKit (#8615) * TestFSMRefSpec: time the state timeout from before it is set, drop the 500 ms cap A_TestFSMRef_must_allow_access_to_internal_state failed in the Akka.Hosting copy with "Block took 00:00:01.82, exceeding 00:00:00.50" on a 2-vCPU Linux agent. The StateTimeout travels scheduler -> mailbox -> ThreadPool-backed dispatcher, and the synchronous Within/AwaitCondition blocked a pool thread while it waited, so a starved agent easily needs more than 500 ms. Both copies (Akka.Hosting.TestKit.Tests and Akka.TestKit.Tests) now await the condition with a Dilated(5s) bound and assert the 80 ms lower bound with a Stopwatch started before SetStateTimeout. Within's clock started after it, so a stall between the two calls could have made the timeout look early. * ReceiveTests: prove the radio-silence reset with a stopwatch instead of a 1.5 s margin WaitForRadioSilenceAsync_should_reset_timer_twice_only returned {1} instead of {1,2} in the Akka.Hosting copy on a 2-vCPU Windows agent. Message 2 was sent 1.5 s after message 1 into a 3 s window that message 1 had just opened, so a 1.5 s oversleep on the test thread pushed it out. Both copies now send 2 only 400 ms after 1, in a 4 s window, and prove the reset from the elapsed time: the silence cannot end before max after 2 was sent, while without a reset it would end about 400 ms sooner. Delays only lengthen the measured time. Renamed to what it tests; the maxMessages violation is already covered by WaitForRadioSilenceAsync_should_fail_immediately_with_bad_input. (cherry picked from commit 0ea28f8) * De-flake scheduler cancel test and Hosting AwaitAssert test (#8712) TaskBasedScheduler_TellScheduler_Cancellation_Tests: a repeater tick that fires before Cancel() runs (test thread stalled past the 150ms interval) sits in the TestActor queue and tripped ExpectNoMsg. Drain in-flight ticks, then require two intervals of silence, bounded by a deadline so a broken cancel still fails. Akka.Hosting.TestKit AwaitAssertTests: convert to AwaitAssertAsync and WithinAsync, and raise the upper bound from 1s (dilated to 2s) to 10s so a starved host cannot trip it. (cherry picked from commit c01ec35) * TCK: give each SaveSnapshot spec actor a fresh name (#8734) The spec stopped an actor, waited for Terminated and recreated it under the same name. The parent frees the name only after the watcher saw Terminated, so the recreate failed with InvalidActorNameException in roughly one run in three. (cherry picked from commit 84461de)
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.
Two timing flakes, each present in both
Akka.TestKit.Testsand theAkka.Hosting.TestKit.Testscopy imported in #8594. Both failed in AOT-stack builds, but neither touches the TestKit. One commit per test.1.
TestFSMRefSpec.A_TestFSMRef_must_allow_access_to_internal_stateFailed on a 2-vCPU Linux agent with:
Block took 00:00:01.8249680, exceeding 00:00:00.5000000.Cause.
SetStateTimeout(100ms)schedules aTimeoutMarker, which the FSM then handles on the ThreadPool-backed dispatcher. The Hosting copy waited with a synchronousWithin+AwaitConditionunder a 500 ms cap, blocking an xUnit worker in the meantime. The core copy is async but has the same cap. Separately,Within's clock started only afterSetStateTimeoutreturned, so a stall between the two calls could make the timeout look early.Change.
await AwaitConditionAsync(..., Dilated(5s)). AStopwatchstarted beforeSetStateTimeoutasserts at least 80 ms passed. A 10 ms scheduler tick can fire the 100 ms timeout at about 90 ms, which still clears 80 ms.2.
WaitForRadioSilenceAsync_should_reset_timer_twice_only→..._should_reset_the_timer_on_each_messageFailed on a 2-vCPU Windows agent: it got
{1}instead of{1, 2}.Cause. Each receipt re-arms the window: a fresh
CancellationTokenSource(max)perReceiveOneAsync, inTestKitBase_Receive.cs:168-183, 245-276. Message 2 was sent 1.5 s after message 1, into a 3 s window that message 1 had just opened, so a 1.5 s oversleep pushed it out.Change.
maxafter message 2 was sent (the CTS timers never fire early), while with no reset it would end about 400 ms sooner. Delays only lengthen the measured time.Tell(3)after a 6 s sleep asserted nothing and is dropped. ThemaxMessagesviolation is already covered byWaitForRadioSilenceAsync_should_fail_immediately_with_bad_input.Verification (local, each test in each project)