Repository navigation
fix(srt): keep the listener alive until a rejected caller sees the verdict - #3887
Conversation
…rdict `Publish::reject` / `Subscribe::reject` only hand the verdict to the listener task; the rejection packet is sent later, when that task drains its response channel. The `rejected()` test moved the `Server` into a task that returned as soon as `reject()` did, so the listener was dropped with the verdict still queued. Its run loop selects the close signal against the response channel, so it could break out before transmitting, leaving the caller to time out instead of seeing ConnectionRefused. Drive the server with `join!` so it stays owned by the test for the whole handshake, and say on `reject()` that the server has to outlive it. Reproduced at 19/20 with the suite at 4+ test threads; 0/120 after, including under CPU load and through nextest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 1 minute. View limit detailsLimit details: You’ve used all 4 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
No issues found. |
|
Assessment
MERGE — deterministic flake fix with no production behavior change. |
|
Auto-merge enabled (squash). Summary of this PR and the merge checks:
This also unblocks #3730, whose (Written by MiMo) |

Problem
dial::tests::publish_rejection_carries_unauthorized_codeand its siblingsubscribe_rejection_carries_unavailable_codefail intermittently in CI withTimedOutinstead ofConnectionRefused(e.g. run 35731120127, on a PR touching no SRT code).Root cause
ConnectionRequest::rejectin srt-tokio only pushesAccessControlResponse::Rejectedonto the listener's response channel. The rejection packet is sent later, whenSrtListenerState::run_loopdrains that channel. That loop'sWaitForInputarm selects the response channel againstclose_recvr, which resolves as soon as theSrtListeneris dropped.The test moved the
Serverinto a spawned task that returned the instantreject()did, so the listener was dropped with the verdict still queued. When the run loop woke, both branches were ready and it could break out before transmitting. The caller then saw nothing and hit the SRT connect timeout.Instrumented run showing it:
The two accept tests are structurally immune:
request.accept()awaitssettings_receiver, which only resolves once the listener has acted on the request, and the task then keeps theServeralive for the connection's lifetime.Candidates ruled out
free_udp_addr()port race: cannot produce this symptom. srt-tokio'sbind_socketsets noSO_REUSEADDR/SO_REUSEPORT, so a stolen port failsServer::bind(...).unwrap()loudly rather than silently swallowing datagrams. Left as is; handing the pre-bound socket toSrtListenervia.socket()would bypass srt-tokio's ownbind_socketand silently drop its 64 KiB UDP send/recv buffer sizing, which is not worth it for a test-only benefit.Fix
Drive the server with
tokio::join!instead of a spawned task, so theServerstays owned by the test body for the whole handshake, and document on bothreject()methods that the verdict is handed to the listener rather than sent, so theServerhas to outlive the client's handshake.moq_srt::runwas already correct: itsServerlives for the entire accept loop, so no production path rejects and then tears the listener down.Verification
cargo nextest run -p moq-srt, 16 threads, loadedjust checkandjust testpass.Public API and wire impact
None. Doc-comment text only on
Publish::reject/Subscribe::reject; the rest is test code. No wire change.Regression test
The fixed test is the regression test: it was already asserting the right thing and now does so deterministically. There is no separate production defect to cover, since the only reject-then-drop sequence was in the test.
🤖 Generated with Claude Code