Skip to content

feat(net): cancel a pending fetchGroup with an AbortSignal - #4546

Merged
kixelated merged 2 commits into
mainfrom
quest/m1/js-fetch-cancel
Sep 30, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m1/js-fetch-cancel

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Problem

A @moq/net caller could not abandon one pending fetchGroup() without closing the track or session (the follow-up #4357 left). Implements quest/m1/js-fetch-cancel.md.

Approach

  • FetchGroupOptions.signal?: AbortSignal, threaded through broadcast.ts (local) and lite/subscriber.ts (wire). The IETF path still rejects fetchGroup and is unchanged.
  • An already-aborted signal rejects with its reason before subscribing or opening any stream.
  • On abort, the caller's mirror is closed and its promise rejects with the signal's reason. Coalesced callers keep sharing the one FETCH stream.
  • The shared stream is cancelled only once every sharer has left. After acceptance the existing demand-driven pump already did this; setup now watches demand too (untilAbandoned), so a fetch abandoned during TRACK_INFO never sends its FETCH, and one abandoned while waiting for acceptance resets the stream with CANCELLED. To make that watch valid from the start, the first caller's mirror is reserved before the fetch starts.
  • Aborting after the promise resolves does nothing; close the group instead (same as connect({ signal })).
  • Small util/abort.ts helper (untilAborted) shared by both paths.
  • Tests: already-aborted, one of two sharers aborting (the other still gets the group, stream not reset), last sharer aborting during TRACK_INFO and during FETCH, plus the local path. All four lite tests fail without the fix.
  • Documented in doc/lib/js/net.md.

Impact

  • Public API: additive FetchGroupOptions.signal in @moq/net.
  • Wire: none new. Abandoning a pending fetch uses the existing reset path with CANCELLED.

Alternatives

  • The signal could also close the resolved group, like fetch() does for a body. Not done: the quest scopes it to a pending fetch, and connect({ signal }) already ignores an abort after it resolves.

Follow-ups

  • None required. Possible: the lite publisher could pass a signal when the peer resets the FETCH it is serving.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits September 29, 2026 15:05
FetchGroupOptions gains `signal`. An abort rejects that caller with the
signal's reason and closes only its share; the coalesced FETCH stream is
cancelled once the last sharer leaves, including during setup. An
already-aborted signal rejects before anything is sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review September 29, 2026 22:50
@coderabbitai

coderabbitai Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 13 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 8040ce9d-e695-4ca8-8c2e-df53de578889

📥 Commits

Reviewing files that changed from the base of the PR and between 4a0c450 and 02f4172.

📒 Files selected for processing (9)
  • doc/lib/js/net.md
  • js/net/src/broadcast.test.ts
  • js/net/src/broadcast.ts
  • js/net/src/lite/subscriber.test.ts
  • js/net/src/lite/subscriber.ts
  • js/net/src/track.ts
  • js/net/src/util/abort.ts
  • quest/m1/README.md
  • quest/m1/js-fetch-cancel.md

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 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-09-29T22:53:23.574362Z 02f4172 Draft marked ready
ℹ️ 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 kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed head: 02f4172

Direction: useful and proportionate. Reserving each caller's mirror before setup, then abandoning the shared fetch only after the final caller leaves, is the right ownership model. A per-caller AbortSignal should not close the track or cancel another caller's fetch.

No actionable defect found in the changed local/lite fetch paths, abort helper, or setup-abandonment cleanup. The tests cover pre-abort, one surviving sharer, and final-sharer cancellation during TRACK_INFO and FETCH. Keeping cancellation scoped to setup, with callers closing an already returned group themselves, is a clear API boundary.

Verification: static diff and surrounding subscriber/broadcast/track cleanup review; no Bun tests executed.

(Written by OpenAI)

@kixelated
kixelated merged commit 2d96757 into main Sep 30, 2026
4 checks passed
@kixelated
kixelated deleted the quest/m1/js-fetch-cancel branch September 30, 2026 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant