Repository navigation
fix(net): read SUBSCRIBE FINs that raced a peer's close - #6741
Conversation
Quest-Claim: 5e1917c3aa2458be
On lite-03/04 the subscription FIN is a track's only end, and the publisher's graceful close drains on its transport acknowledgement, so the close can reach the relay before the relay reads the FIN. The subscriber half then aborted the track instead of finishing it. After the closed transport's group streams drain, give each source one last poll so a subscription reads what the peer already delivered. A closed session's grants end with it, which is not a revocation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 3 minutes. View limit details
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 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: aa032c8
No actionable bugs found. Draining received group streams before polling subscription completions preserves their destination state, and letting the closed session determine track termination avoids misclassifying teardown as authorization revocation. This receiver-side ordering fix is simpler than adding a publisher timeout or a new FIN handshake for older peers. The expanded three-track regression covers simultaneous completions across close and abort paths.
Verification: static inspection of the complete patch, relevant lifecycle/auth/task code and regressions. Tests and real-transport interoperability were not run.
Since #6741 a closed lite session drains its sources in a fixed order, so the catalog failure always reaches the cursor first and the loop waiting for both orders could never finish. Each disconnect now runs once and accepts any typed failure; export unit tests cover the timeline failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
On lite-03/04 a subscription's FIN is the track's only end (no SUBSCRIBE_END). A publisher's graceful close drains on the transport's acknowledgement of that FIN, so the close can reach a relay before the relay reads the FIN. The relay's subscriber half then never polled the subscription again: its publisher half failed on the closed accept first, the drain read only group streams, and cleanup aborted every track. Downstream, a finished track read as
Unroutableinstead of finished. Found byrelay_upstream_closein moq-dev/moq#6660.Approach
Fix the receiver's close ordering, with no extra wait or timer:
SubscriberDriver::poll_drain: once the closed transport's group streams drain, poll the sources once, so each subscription reads what the peer already delivered. A buffered FIN takes the existing Tail path, which finishes the track on a closed session. A subscription without one hands the track back as before. Serve machines still wait for the group streams, since ending a subscription removes the state the tails are delivered into.TrackServeRun: a closed session's auth grants end with it, which no longer counts as a revocation. Without this the final poll aborted tracks withUnauthorized(caught bysource_errors::track_in_flight_through_a_dead_upstream_is_unroutable).relay_upstream_closenow finishes three tracks together so several SUBSCRIBE FINs are pending at the close, and runsCloseon lite-03/04 too.Choices made without asking:
Impact
Alternatives
Follow-ups
js/netmay have the same ordering on a peer's close; not checked here.Checks
just check: passed.Closefailed withErr(Stream(Unroutable))and no frames before the fix.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)