Repository navigation
De-flake InboxSpec: receive through ReceiveAsync so a deadline failure surfaces as TimeoutException - #8564
Merged
Aaronontheweb merged 2 commits intoSep 10, 2026
Conversation
Aaronontheweb
added this pull request to stack #8567
September 10, 2026 03:21
Aaronontheweb
force-pushed
the
fix/inbox-spec-receive-async
branch
from
September 10, 2026 04:58
87b6b78 to
57b2682
Compare
Aaronontheweb
force-pushed
the
fix/inbox-spec-receive-async
branch
from
September 10, 2026 13:14
57b2682 to
f1ce4d7
Compare
…e surfaces as TimeoutException, and restore the exact-type assertions Inbox.Receive(timeout) waits on the wall clock while the inbox actor schedules its own deadline for the same duration; when that deadline wins the race, Task.Wait rethrows the actor's Status.Failure(TimeoutException) wrapped in AggregateException instead of the bare TimeoutException the tests expect. Awaiting ReceiveAsync instead surfaces the exception directly with no race, so this migrates every InboxSpec receive call to the async API and drops the IsTimeoutException either-type workaround added by an earlier fix.
…ct exception type on the negative-deadline fact
Task.Run + Task.Delay staggers the two ReceiveWhere calls without parking
a pool thread; ReceiveWhere itself has no async overload and isn't in the
race, so it stays as-is.
Traced the negative-deadline fact through Inbox.Actor.cs's Kick handling
and FutureActorRef<object>.TellInternal: a deadline already in the past
always produces a bare TimeoutException("Deadline passed"), never
anything else, so ThrowsAnyAsync<Exception> is tightened to
ThrowsAsync<TimeoutException>.
Aaronontheweb
force-pushed
the
fix/inbox-spec-receive-async
branch
from
September 10, 2026 14:54
f1ce4d7 to
bedcdad
Compare
Aaronontheweb
added a commit
that referenced
this pull request
Sep 12, 2026
…e surfaces as TimeoutException (#8564) * De-flake InboxSpec: receive through ReceiveAsync so a deadline failure surfaces as TimeoutException, and restore the exact-type assertions Inbox.Receive(timeout) waits on the wall clock while the inbox actor schedules its own deadline for the same duration; when that deadline wins the race, Task.Wait rethrows the actor's Status.Failure(TimeoutException) wrapped in AggregateException instead of the bare TimeoutException the tests expect. Awaiting ReceiveAsync instead surfaces the exception directly with no race, so this migrates every InboxSpec receive call to the async API and drops the IsTimeoutException either-type workaround added by an earlier fix. * InboxSpec: queued-queries fact awaits delays instead of sleeping; exact exception type on the negative-deadline fact Task.Run + Task.Delay staggers the two ReceiveWhere calls without parking a pool thread; ReceiveWhere itself has no async overload and isn't in the race, so it stays as-is. Traced the negative-deadline fact through Inbox.Actor.cs's Kick handling and FutureActorRef<object>.TellInternal: a deadline already in the past always produces a bare TimeoutException("Deadline passed"), never anything else, so ThrowsAnyAsync<Exception> is tightened to ThrowsAsync<TimeoutException>. (cherry picked from commit 989e299)
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.
Stacked on #8563.
What changes
InboxSpecreceives throughReceiveAsyncinstead of the blockingReceive, and the two facts that assert a timeout assert the exact exception type again.ReceiveAsync.Inbox_have_maximum_queue_sizeassertsTimeoutExceptionwithAssert.ThrowsAsync.Inbox_have_a_default_and_custom_timeoutsgets its exact-type assertions back. Fix flaky tests: InboxSpec, ShardRegionSpec, and scheduler interval test #8035 had loosened them to accept anAggregateExceptionas well, through a helper that is now deleted.ReceiveWherecalls stay as they are; there is no async overload, and their timeouts never expire in these facts. The queued-queries fact runs them underTask.Runwith awaited delays instead of thread sleeps.TimeoutExceptionexactly. A deadline already in the past makes the inbox actor kick itself at once and answer with that one exception type, so nothing else can come out.No change to
Inboxitself. It is deprecated and slated for removal in #7946.Why
Build 131326, Linux unit tests, on a PR that touched a different spec:
Inbox_have_maximum_queue_sizeexpectedTimeoutExceptionand got anAggregateExceptionwrappingTimeoutException("Deadline passed").The sync
Receive(timeout)blocks ontask.Wait(timeout). The inbox actor schedules its own deadline for the same duration and faults the task with aStatus.Failurecarrying the timeout. When the actor's deadline fires before the wall-clock wait gives up,Task.Waitthrows the aggregate, and the unwrap code written for the faulted case, right after the wait, never runs. Which side wins is a race between the scheduler and the wall clock over the same second. The same test was reported flaky in 2014 (#340), and the sibling fact in 2025 (#7934), which was closed as won't-fix because the Inbox is going away; #8035 then loosened the sibling's assertion instead.ReceiveAsyncis theAskwith the deadline and no wall-clock wait, so awaiting it surfaces the actor's timeout directly. That removes the race rather than tolerating either outcome, and it is the async form the touched-file rule asks for.How it was checked
dotnet build src/core/Akka.Tests -c Release -warnaserrorclean. TheInboxSpecclass run ten times: 7 passed each time. The grep for blocking receives, waits, results, and synchronous throw assertions on the file returns onlyReceiveAsyncandReceiveWherecalls. Test-only change. No ledger entry.Second commit
From the adversarial review: the two
Task.Factory.StartNewblocks with thread sleeps becameTask.Runwith awaited delays, and the third timeout fact's any-exception assertion became the exact type, which the negative-deadline path produces deterministically.InboxSpecrun five times: 7 of 7 each time.