Summary
A publisher finishes its track and awaits close(), which returns Ok(()). The subscriber does not get all of the track: the final group is missing or cut, and the subscription ends with an error.
Expected
When close() returns Ok, the subscriber reads every frame of the finished track, then a clean end (Ok(None)).
Observed
On main @ 6a01640. The test is one commit on the branch kidq330/bug/close_discards_received_tail, file rs/moq-net/tests/close_tail.rs, needs a small ack_fins() switch in the test mock:
git fetch https://github.com/kidq330/moq kidq330/bug/close_discards_received_tail
git checkout FETCH_HEAD
cargo test -p moq-net --test close_tail
One session over the mock transport, paused clock, fails on every run:
moq-lite-05: the close returned Ok, the subscriber got ["head"], err=Some(Session(Cancel))
The subscriber reads a head group; the publisher writes the final group, finishes the track and awaits Session::close(). The final group is complete in the subscriber's transport before the close. The test adds one switch to the test mock, ack_fins(): a FIN is acknowledged as soon as it is sent, as on a real transport. By default the mock acknowledges a FIN once the peer's application is done with the stream. A second test keeps the session open; it passes.
Impact
Any publisher that ends a broadcast and leaves: a file import, an encoder stopping, a GStreamer pipeline going to NULL. Viewers lose the end of the last group and see an error where the end of the track should be. The publisher is told the close succeeded, so it has nothing to retry on.
With moqsink → relay → moqsrc the last frame of 120 is missing in 3 of 10 rounds over TCP and 1 of 10 over QUIC, and moqsrc posts a session error, not EOS, in every round.
Context
#4430 added close().
(Written by Claude Fable 5.1)
Summary
A publisher finishes its track and awaits
close(), which returnsOk(()). The subscriber does not get all of the track: the final group is missing or cut, and the subscription ends with an error.Expected
When
close()returnsOk, the subscriber reads every frame of the finished track, then a clean end (Ok(None)).Observed
On
main@ 6a01640. The test is one commit on the branchkidq330/bug/close_discards_received_tail, filers/moq-net/tests/close_tail.rs, needs a smallack_fins()switch in the test mock:One session over the mock transport, paused clock, fails on every run:
The subscriber reads a head group; the publisher writes the final group, finishes the track and awaits
Session::close(). The final group is complete in the subscriber's transport before the close. The test adds one switch to the test mock,ack_fins(): a FIN is acknowledged as soon as it is sent, as on a real transport. By default the mock acknowledges a FIN once the peer's application is done with the stream. A second test keeps the session open; it passes.Impact
Any publisher that ends a broadcast and leaves: a file import, an encoder stopping, a GStreamer pipeline going to NULL. Viewers lose the end of the last group and see an error where the end of the track should be. The publisher is told the close succeeded, so it has nothing to retry on.
With
moqsink→ relay →moqsrcthe last frame of 120 is missing in 3 of 10 rounds over TCP and 1 of 10 over QUIC, andmoqsrcposts a session error, not EOS, in every round.Context
#4430 added
close().(Written by Claude Fable 5.1)