Repository navigation
fix(mux): a TS export drains a left publisher's buffered tail before it ends - #7137
Conversation
Quest-Claim: f4e87fd0bf84c696
…it ends When the publisher left, the export reported the end at once and left up to --delay of released media in its jitter buffer. A follower stops polling while it waits, so that tail went out late, in one burst behind the gap, when the publisher or a stitched replacement came back. The nightly stitch test caught it as old-program packets after its mark, so the first packets it checked on PIDs 256, 257 and 17 carried no break flag. The export now stops a left publisher's input but plays out what it buffered on schedule, and only then reports the cause. The retired program keeps its catalog, since the follower subscribes a return with its format. 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 1 minute. 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: 588dcf6
No actionable bugs found in the changed paths. Draining already-buffered media before reporting a lost publisher is a sound direction: it prevents the follower from parking a live output tail, while preserving the existing pacing and replacement handoff. Sharing retirement logic is simpler than a second drain mechanism; retaining the catalog for resubscription and clearing the saved cause on resume fit the follower's lifecycle. The delayed start of the follow timeout is documented.
The paused-time regression checks both the buffered tail and its release timing without weakening the stitch assertion. Static review of the diff and surrounding export/follower code only; I did not run tests or independently reproduce the nightly failure.
|
Maintainer decision: keep playing out a departed publisher's buffered media on schedule before following or exiting (no media lost; --follow and the lost-publisher exit start up to --delay later). (Written by Claude Opus 5.5) |
|
Merge summary for head
(Written by Claude Opus 5.5) |
|
Merged (Written by Claude Opus 5.5) |
Problem
The nightly CLI-export job failed
export::a_restarted_publisher_is_a_program_switch_with_stitchat "every PID flags the break" ([256, 257, 17]). It still reproduces on current main (53c0dcd685), so neither moq-dev/moq#7049 nor moq-dev/moq#7048 fixed it.The discontinuity signaling itself was correct. A dump of the export's output showed the new program's first packet on every PID (PCR PID 256, PAT, PMT, SDT 17, audio 257) carrying
discontinuity_indicator. The unflagged packets after the test's mark were the old program's: about 200 packets of the interrupted publisher's buffered tail. They went out about 2 s after the mark, in one 30 ms burst, when the replacement arrived.Root cause: when a publisher left (
Unroutable),Export::poll_nextreturned the error right away, with up to--delayof media still in its jitter buffer. TheFollowerstops polling the export while it waits for a return. That tail then sat until the replacement (or the same instance) came back, and went out late, behind the gap.moq-dev/moq#6919 made this visible: it keeps the old program running while a replacement acquires. Before that, a switch discarded the old program, stale tail included. The last passing nightly ran at
22808bbb2f, and #6919 is in the range after it.Change
rs/moq-mux/src/container/ts/export.rs: a publisher that leaves gets its input stopped at once, the way an expired follow stops it. What it already buffered goes out on schedule, and only then does the export report the cause. This applies to failures fromprepareand from the in-loop refill. The retirement half ofstop_oldis nowretire(), which both paths share. A program whose publisher left keeps its catalog, because the follower reads its format to subscribe a return. A resumed program clears its pending cause.rs/moq-mux/src/container/ts/export_test.rs:a_publisher_that_leaves_drains_its_buffered_tail_before_the_endcovers this deterministically with paused time. It fails on main ("a tail went out after the publisher left"), since the export ends at once with the tail still buffered, and passes with the fix.doc/bin/cli.md: says a publisher that leaves still gets its buffered output out on schedule before the follow waits.quest/m0/nightly/stitch-discontinuity.md.The end-to-end assertion is unchanged.
Choices made without the maintainer
--follow(and exit 1 on a lost publisher) starts up to--delaylater.Validation
just check origin/mainon the merged head: 4153 Rust tests passed (60 skipped), plus clippy, JS, markdown, quest, shell and toml checks.just rs cli-exporton the merged head: 14 of 14 passed, including the previously failing stitch test andthe_same_instance_within_the_follow_continues.cargo test -p moq-mux: 1837 passed before the main merge.Follow-ups
quest/m1/ts-reliability/step-restart.mddepends on stitch signaling. Signaling was fine; its stitch test needed this drain.stop_olddrops the old catalog on follow expiry and the pending replacement is then cancelled,Followercould panic incatalog_format("selected catalog"). This PR does not touch that path; it may be worth a deterministic test.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)