Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions drafts/draft-lcurley-moq-lite.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ See [Transports](#transports) for the bindings.

How the underlying connection is authenticated is out-of-scope for this draft.

A subscriber that holds an Auth Stream and an Announce Stream needs credit for at least 4 concurrent bidirectional streams to establish a subscription.
AUTH and ANNOUNCE occupy two streams for the session lifetime, and TRACK is briefly held alongside SUBSCRIBE, requiring two more.

## Transports {#transports}
moq-lite defines five transport bindings.
All five carry the same control and data streams defined elsewhere in this document; they differ only in how QUIC streams are multiplexed onto the underlying connection.
Expand Down
2 changes: 1 addition & 1 deletion quest/m1/stream-credit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ receiving every group, and nothing hanging.

## Required

- [A departed subscription releases its streams](/quest/m1/stream-credit/release-on-leave.md) - on lite-07 a subscription whose reader left frees its upstream streams, so 3 slots serve the next one
- [An abandoned subscription setup releases its streams](/quest/m1/stream-credit/release-on-leave.md) - release TRACK and pending SUBSCRIBE when demand leaves during setup
- [Open streams](/quest/m1/stream-credit/open-streams.md) - each session lists its open streams and, where the transport can tell, which are fully acknowledged
- [Reset fallback](/quest/m1/stream-credit/reset-fallback.md) - a waiting higher-priority open resets the lowest-priority stream, one reset in flight per waiting open
- [Takeover](/quest/m1/stream-credit/takeover.md) - on lite-07 a higher-priority group takes over an acknowledged stream, and a group that lost its stream resumes
39 changes: 22 additions & 17 deletions quest/m1/stream-credit/release-on-leave.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
# [S] A departed subscription releases its streams
# [S] An abandoned subscription setup releases its streams

## Goal

On lite-07, when a subscription's last reader leaves, every stream it held
upstream is released, so the credit returns for the next subscription. A
relay test with exactly 3 bidirectional stream slots serves a second
subscription after the first leaves, as it already does on moq-transport-22
and on lite-07 with 4 slots.
On lite-07, a subscription whose last reader leaves while SUBSCRIBE is still
opening or awaiting its answer releases its upstream TRACK and pending
SUBSCRIBE, so their credit can serve later requests.

## Plan

Found 2026-11-04 by the scheduler's relay test
(`a_subscription_past_the_credit_is_served_once_credit_returns`, from
[moq-dev/moq#7894](https://github.com/moq-dev/moq/pull/7894)): on lite-07 with exactly 3 bidirectional slots, a second
subscription is never served after the first leaves, while 4 slots work and
moq-transport-22 works with 3. The likely cause is a stream the departed
subscription keeps open upstream (its request stream, or a companion such as
the Tracks stream) after its reader leaves. Reproduce it with the 3-slot
relay test first, find which stream stays open and on which side, fix it, and
set that relay test's credits back to the tight case. With opens now waiting
for credit instead of failing, a leaked stream stalls later subscriptions
silently, and low-credit peers such as browsers hit it first.
Decided 2026-11-05 (maintainer, /quest-plan): ✅ Keep the TRACK/SUBSCRIBE
handshake and document the minimum of four concurrent bidirectional streams.
AUTH and ANNOUNCE hold two slots for the session lifetime; TRACK is briefly
held alongside SUBSCRIBE. Three slots cannot establish the first subscription.
Rejected: metadata on SUBSCRIBE (overlaps other lite-07 work and saves no round
trip), and releasing TRACK early during a live setup.

The established-subscription regression
`a_subscription_past_the_credit_is_served_once_credit_returns` already passes
with four slots. Keep that budget. The three-slot reproduction did not show a
departure leak.

Local review identified remaining pending-setup cleanup: `ServeLoop::poll` in
`ServeMode::Establish` waits on establishment without observing lost demand,
while holding `HeldTrack`. Reproduce abandonment with at least four slots,
keeping the publisher and route live, then ensure both the TRACK hold and the
pending SUBSCRIBE registration are released when demand leaves. Preserve the
hold while demand remains. Cover Rust and its JS counterpart where applicable.
4 changes: 2 additions & 2 deletions rs/moq-net/tests/integration/stream_credit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ async fn one_stream_credit_serves_every_backlogged_group() {
/// subscription past the publisher's credit is served once an earlier one leaves.
#[kio::test]
async fn a_subscription_past_the_credit_is_served_once_credit_returns() {
// Room for the bidirectional streams the session holds before the second subscription:
// the second then waits for one of the first's.
// lite-07 needs 4: session-long AUTH and ANNOUNCE plus TRACK held until SUBSCRIBE answers.
// Three is below the setup minimum; the second subscription waits for the first's credit.
for (version, credit) in [("moq-lite-07-wip", 4), ("moq-transport-22", 3)] {
let version: Version = version.parse().unwrap();
let publisher = origin(1);
Expand Down
Loading