Skip to content

De-flake TcpConnectionOwnershipDisposalSpec: keep the close from finishing before the rejected write lands - #8661

Merged
Aaronontheweb merged 1 commit into
akkadotnet:devfrom
Aaronontheweb:fix/deflake-tcp-ownership-closing
Sep 29, 2026
Merged

Aaronontheweb merged 1 commit into
akkadotnet:devfrom
Aaronontheweb:fix/deflake-tcp-ownership-closing

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Member

OwnedWrite_ClosingBehaviour_rejection_disposes_owner_before_CommandFailed sends Close, then an owned Write, and expects the Write to be rejected while the connection is closing.

Race: on an idle connection the graceful close completes through self-messages (TransportOperationCompleted, ReadPumpCompleted) within a few ms, and the actor stops. If the test thread is preempted between the two sends, which is realistic on 2-vCPU agents where Close wakes 3–4 threads, the Write is dead-lettered. The handler gets Closed instead of CommandFailed, and the owner is never disposed. Same-sender FIFO doesn't help, because the messages that finish the close come from the actor itself.

  • Forced repro: a 20 ms sleep between the sends fails 3/6; 50 ms fails 6/6.
  • Natural rate: rare (0/56 full IO-suite runs locally under CPU stress). It was seen once on unmodified dev.

Fix (test only): before Close, park 4 MB of output that the client doesn't read, using 16 KB socket buffers (the same technique as TcpConfirmedCloseSpec). The close can't finish until the test drains it, so the Write always lands in ClosingBehaviour. The test then drains, checks that the blocker arrives intact followed by EOF (the rejected bytes never hit the wire), and expects Closed and Terminated. Every expectation in the test now has an explicit timeout.

Verification:

The other seven tests in the spec were checked for thread-level races (dispose counts use Interlocked/Volatile, the pool is per test and thread-safe). None were found.

…shing before the rejected write lands

An idle graceful close finishes in a few ms, so a test thread preempted
between Close and Write could see the Write dead-lettered (Closed instead
of CommandFailed). Park unread output first so the connection stays in
ClosingBehaviour until the test drains it.
@Aaronontheweb
Aaronontheweb merged commit 4316f71 into akkadotnet:dev Sep 29, 2026
16 checks passed
@Aaronontheweb
Aaronontheweb deleted the fix/deflake-tcp-ownership-closing branch September 29, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant