Skip to content

fix(net): a restarted publisher wins over its lingering session on release - #6697

Merged
kixelated merged 1 commit into
releasefrom
backport/restart-lingering-session
Oct 25, 2026
Merged

kixelated merged 1 commit into
releasefrom
backport/restart-lingering-session

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Backport of #6452 to release, using the approach from #6435.

Problem

A publisher that dies without a clean close (SIGKILL, a dropped uplink) leaves its session on the relay until QUIC idles it out. The restarted process announces the same path under a new first hop. route_order hashes both routes before the newest-announcement tiebreak, so the dead session keeps the path about half the time. The hash is per path, so every viewer of that broadcast lands on the dead session. Their catalog.json request waits until the old session idles out. Through a cluster hop the downstream relay fails the same way, because the origin relay picks the dead route for the peer's upstream too.

End to end with moq-relay 0.17.5, ffmpeg | moq import ts SIGKILLed and restarted at once, then a burst of 8 to 13 viewers per step, 6 steps per run:

Relays Viewers on the origin relay Viewers via a cluster peer
0.17.5 4 of 6 steps failed for every viewer 3 of 6 steps failed for every viewer
this branch 6 of 6 clean 6 of 6 clean
main (with #6452) 6 of 6 clean 6 of 6 clean

Change

route_order hashes only routes a cluster peer forwarded (RouteEntry::peer). No other node ranks a route that entered on this relay, so convergence does not need the hash there. Such a route now falls through to Reverse(entry.id), and the newest announcement wins as soon as it lands.

main's #6452 keeps the hash for a local prefix claim, to preserve per-path spreading of a directly connected pool. release keys the hash on the route's own prefix and has no per-path spreading, so the peer flag alone is the equivalent condition here.

Side effect: at an otherwise exact tie, a route that entered here beats a peer-forwarded one (hash 0 versus a hash). A peer route's chain is at least one hop longer, so this only matters for an exact tie.

Tests

  • restart_while_the_old_session_lingers_wins (new rs/moq-net/tests/restart_lingering.rs): the old session goes silent, the publisher restarts under another hop, and a viewer subscribes. It runs both hop orders on moq-lite-06, moq-lite-07-wip, and moq-transport-22. It fails on release with moq-lite-06 (1 -> 4): subscribe hung.
  • a_reconnect_under_a_new_hop_wins_over_the_old_session (origin unit test, from fix(net): a reconnecting publisher wins over its lingering session on release #6435): covers named ([10]/[11]) and relay-stamped ([10, 0]/[11, 0]) reconnects in both orders.
  • just check origin/release: passed.

Impact

  • Public API: none. Only the Route::cost doc comment changes, to describe the new ordering.
  • Wire: none.
  • Behavior: on a relay, routes announced to it directly no longer use the hash tiebreak, so the newest one wins. This also applies to local equal-cost prefix claims, which now go to the newest claimant instead of a fixed hash winner. Peer-forwarded routes rank exactly as before.
  • js/net is unchanged: a JS origin never ranks a relay's routes.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

…lease

Backport of #6452. A publisher that restarts without a clean close leaves its
old session on the relay until QUIC idles it out, and the restart announces the
same path under a new first hop. route_order hashed both, so the dead session
kept the path half the time and every viewer of that broadcast waited on it.

Only a route a cluster peer forwarded is hashed now; one that entered here
falls through to the newest announcement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T02:56:19.718585Z 5511441 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary: no changes made by the merge pass. Codex reviewed head 5511441 with no findings, all required checks passed, and quest check --base origin/release is clean. Landing as a merge commit, per CONTRIBUTING.md for PRs into release.

(Written by Claude Opus 5.5)

@kixelated
kixelated merged commit 3db33f6 into release Oct 25, 2026
7 checks passed
@kixelated
kixelated deleted the backport/restart-lingering-session branch October 25, 2026 04:04
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