Repository navigation
quest: plan Demand everywhere and IETF FETCH abandonment #4696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # [M] Demand is the one way to watch subscribers | ||
|
|
||
| ## Goal | ||
|
|
||
| On `dev`, every model handle that serves subscribers watches them through a | ||
| `Demand` handle returned by `demand()`: `track::Request`, `group::Request`, | ||
| `group::Producer`, and `broadcast::Producer`. Their own | ||
| `used`/`unused`/`is_used`/`poll_unused` copies are gone, in Rust and `js/net`. | ||
| moq-ffi then exposes the same handle on its request and producer types through | ||
| the [FFI shape](/quest/m1/ffi-shape/README.md) line, so a binding's fetch | ||
| handler can see a group request abandoned. | ||
|
|
||
| ## Plan | ||
|
|
||
| Facts (2026-10-01): `track::Demand` and `broadcast::Demand` already exist. | ||
| [#4528](https://github.com/moq-dev/moq/pull/4528) (the track-demand quest) moved | ||
| `track::Producer` to `demand()` on `dev`, and deliberately kept group and | ||
| broadcast `used`/`unused`, since group demand drives fetch coalescing. | ||
| `broadcast::Producer` is already `demand()`-only, with `used`/`unused` on | ||
| `broadcast::Demand`; there is no `group::Demand` yet. | ||
| `track::Request` and `track::Dynamic` have `poll_unused`, and #4691 added | ||
| `group::Request::poll_unused`. moq-ffi wraps only `track::Demand` | ||
| (`MoqTrackDemand`); `MoqGroupRequest` and `MoqTrackRequest` have no demand. | ||
|
|
||
| Decided (2026-10-01): | ||
|
|
||
| - ✅ Everything under `Demand`, reversing track-demand's call to keep group and | ||
| broadcast `used`/`unused`. Rejected: Requests only. | ||
| - ✅ The binding exposure follows this quest in the FFI shape line instead of | ||
| wrapping `poll_unused` now. Rejected: a standalone moq-ffi quest for | ||
| `poll_unused`, and waiting in m2 for a consumer. | ||
| - ✅ m1, ahead of FFI shape, so the bindings expose `Demand` once. | ||
|
|
||
| - ✅ One type per level (`track::Demand`, `group::Demand`, | ||
| `broadcast::Demand`) with the same method set, like the two that exist. | ||
| Rejected: one generic `Demand`, which erases level-specific state such as | ||
| track priority. | ||
|
|
||
| Keep fetch coalescing's group demand semantics, and keep `abort_unused` where | ||
| its race still needs an owner. | ||
|
|
||
| Public API: breaking on `dev` in moq-net and `@moq/net`. Wire: none. | ||
|
|
||
| ## Related | ||
|
|
||
| - [IETF FETCH abandonment](/quest/m1/ietf-fetch-abandonment.md) - first new consumer of group request demand; can ship on `poll_unused` without waiting for this |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # [S] An abandoned IETF group FETCH is cancelled | ||
|
|
||
| ## Goal | ||
|
|
||
| When the last reader leaves a group that the Rust moq-transport subscriber is | ||
| fetching upstream, it cancels that FETCH (STOP_SENDING plus a reset of the | ||
| request stream, or FETCH_CANCEL on drafts that define it), before and after | ||
| FETCH_OK, the same as an idle SUBSCRIBE and the lite FETCH after #4691. The | ||
| partial group aborts with `Error::Cancel` and never ends clean. | ||
|
|
||
| ## Plan | ||
|
|
||
| Facts (`origin/main`, 2026-10-01): `run_group_fetch` in | ||
| `rs/moq-net/src/ietf/subscriber.rs` sends the FETCH and waits only for the | ||
| request stream to close or the group slot to finish. It never watches demand. | ||
| It is cancelled only when its whole subscription ends. The subscribe path | ||
| already polls `poll_unused` and calls `cancel_subscribe`. Rust already encodes | ||
| and decodes `ietf::FetchCancel` (0x17, `rs/moq-net/src/ietf/fetch.rs`) and the | ||
| adapter routes it, but `run_group_fetch` never sends it. JS never issues an IETF FETCH (`fetchGroup` refuses on | ||
| moq-transport), so it is out of scope. | ||
|
|
||
| Decided (2026-10-01): cancel after the answer too, matching SUBSCRIBE; the | ||
| fetched group is not filled into the cache for absent readers. Reuse | ||
| `group::Request::poll_unused` from #4691, or `demand()` if | ||
| [Demand everywhere](/quest/m1/demand-everywhere.md) lands first. Send the | ||
| existing `FetchCancel` on the drafts that define it (14 to 16) and reset the | ||
| request stream on later drafts, which removed FETCH_CANCEL. | ||
|
|
||
| Tests: a mock-time test abandons a group FETCH before and after FETCH_OK and | ||
| asserts the upstream stream is cancelled. | ||
|
|
||
| Public API: none. Wire: none. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: moq-dev/moq
Length of output: 18216
🌐 Web query:
IETF MoQ Transport drafts 14 15 16 17 FETCH_CANCEL STOP_SENDING request stream data stream cancellation requirements💡 Result:
🏁 Script executed:
Repository: moq-dev/moq
Length of output: 20296
🏁 Script executed:
Repository: moq-dev/moq
Length of output: 24692
Specify the cancellation stream for each draft.
Drafts 14–16 require
FETCH_CANCEL;STOP_SENDINGon an open FETCH data stream is optional. Draft 17 requiresSTOP_SENDINGon the bidirectional FETCH request stream; stopping the data stream is optional. The current wording does not identify this target and could leave FETCH state active if it stops only the data stream.Suggested wording
🤖 Prompt for AI Agents