Repository navigation
quic: is stream priority compatible to w3c webtransport sendgroups ? #63654
Description
Activity
- addedquicIssues and PRs related to the QUIC transport implementation.Issues and PRs related to the QUIC transport implementation.
on Jun 10, 2026 Hi! I've opened a PR to align this: #64454.
I introduced the numeric
sendOrderoption to align Node's experimental QUIC stream priority semantics with W3C WebTransport priority semantics:sendOrderaccepts an integer in the range[0, 7], representing the raw QUIC stream urgency value (where lower value = higher priority).- Passed as an option during stream creation (via
createBidirectionalStreamorcreateUnidirectionalStream) or set viasetPriority(), it overrides the default string-basedprioritylevel. - The
prioritygetter is updated to returnsendOrderalongsidelevelandincrementalproperties, exposing the exact urgency level of the stream. - Validates the range and type of
sendOrderthrowingERR_OUT_OF_RANGEorERR_INVALID_ARG_TYPErespectively.
I verified the implementation by updating the HTTP/3 stream priority test suite in
test/parallel/test-quic-h3-priority.mjs. All tests and ESLint formatting rules pass 100% cleanly.@SparshGarg999
But this lacks the sendGroups. And think it should be something handled upstream in ngtcp2.
And sendOrder in W3C is not limited to {0,7].Hi! I opened a PR (#64454) to try to map
sendOrderto the raw QUIC urgency parameter, but after discussion with reviewers, I've closed it.Since WebTransport's
sendOrderis a signed 64-bit integer (with opposite priority direction) and requiressendGroups(which ngtcp2 doesn't expose yet), full alignment is a much larger architectural change that needs to be handled upstream in ngtcp2 first.- added a commit that references this issue
on Jul 12, 2026 - addedwebtransportIssues and PRs related to the WebTransport API.Issues and PRs related to the WebTransport API.
on Aug 8, 2026 Coming back to this after it was mentioned in the QUIC meeting yesterday: I think we can actually remove some priority API to simplify things first, and then I think webtransport vs HTTP/3 priorities are actually different (opposite) things anyway: priority signalling vs local scheduling. I think there's a reasonable path to clean it up and support this all nicely, suggestion at the bottom.
Context first:
For HTTP/3, a client can tell the server the priority of a request with a header (
priority: u=0) or with PRIORITY_UPDATE frames. We supportpriorityandincrementaloptions for signalling the initial priority of a request, but these are currently broken and have never worked, because they try to send a PRIORITY_UPDATE frame before the stream is open and ignore the error. In reality, this should just set the header, but I don't think we need a special option for that anyway - people can set a header by themselves, which also avoids awkward questions like conflicting options{ headers: { priority: 'u=9' }, priority: 'high' }. HTTP libs on top (universal server fetch) can implement any priority API they like (with a single API that covers H1 + H2 + H3 somehow) and we can don't have to care. We should drop this option I think.We have
setPrioritytoo, for changing headers on requests in flight. This should indeed use PRIORITY_UPDATE frames on the client side. Nice to have, but niche, browsers apparently support it but use it very rarely, just to bump priority on requests like images that scroll into view while pending. Current name sounds a bit like it sets local state instead of sending a frame, which is a bit odd imo.For webtransport though, priority is a totally different thing, I didn't realise but it's local priority only - unlike HTTP/3 priorities, it doesn't send anything to the remote peer. There is no WT priority signalling mechanism to implement. The APIs sound the same, but they're opposite directions:
h3ReqStream.setPriority('high')tells the remote peer to respond ASAP (but changes nothing locally). HypotheticalwtStream.setPriority('high')would tell our local packet scheduler to send our data ASAP (and tells the remote peer nothing). They shouldn't really use the same API. In theory you could even want to do both in different directions: sending a request with high local scheduling but low response priority (e.g. error reporting: put this on the wire ASAP, but I don't care about the response).For QUIC and all datagrams, we control scheduling fully ourselves, for H3/WT, it's managed by nghttp3. Today, nghttp3 scheduling on servers mirrors the request priority by default (can override with nghttp3_conn_set_server_stream_priority), but for clients there's no API to control outbound scheduling at all. That means if you set a client stream to high priority with nghttp3, it signals to the remote peer, but local outbound scheduling priority stays the same. For WT, in the current draft it seems you can't control WT scheduling at all, it's hardcoded.
Imo we should change this upstream: propose a single 'set scheduling priority' API that you can call on any nghttp3 stream, including requests and WT (subsuming nghttp3_conn_set_server_stream_priority). Plumbing is all there, just needs an API to expose it.
For webtransport, since this isn't actually part of the protocol, Node can expose any form of API we like - we can match w3c if we want to, but it's just a JS API and we presumably won't perfectly match the rest of their API anyway so it doesn't make a huge difference.
Would be nice to have the same local scheduling API for QUIC too though - the concept & motivation for QUIC & WT scheduling is identical, no reason not to support both.
How about we aim towards:
- Drop the
priority&incrementalsignalling options. In H3 requests, just set the header manually. Everywhere else it's impossible to signal priority. - Keep
setPriority(maybe rename tosendPriorityUpdateto clarify?) for priority changes, but only support it for HTTP/3 requests. Servers can't send PRIORITY_UPDATE, QUIC/WT have no signalling. - Add a
localPriorityoption andsetLocalPriority()method (names to bikeshed) for local scheduling of a stream - how outbound traffic is prioritised. - Use that to support local scheduling with one API that works the same everywhere: H3, WT, QUIC.
- This implies nghttp3 changes, since scheduling is currently impossible for H3 clients & all WT.
- For H3 received request streams, the default is the signalled remote priority, for everything else it's some fixed middle value.
- For the actual format of
localPriorityto control the local schedule: I think this depends a lot on nghttp3. If that sticks to the H3 format (urgency 0-7 + incremental flag) for WT as well (seems likely) then the easy option is to do the same in Node, and expose that one format everywhere. Is that OK? It's not as granular as the W3C option (2^64 order ids + groups) but it should cover the essentials and it's simple. We could extend this backward compatibly in future with extra fields if we really need to (and if nghttp3 agrees).
All in, that gives us a single API (
localPriority) for local scheduling in the same way everywhere, and a specific h3-client-only API (sendPriorityUpdate) for the "send a priority frame" signalling, which is only actually possible in that one scenario.What do you think @nodejs/quic? Next step would be to discuss with nghttp3 to expose scheduling there.
- Drop the
Forgot to link this in the morning ngtcp2/nghttp3#559 I have asked upstream.
Reacted by Tim PerryI think this is fine for the short term. I'm not entirely happy with the rather unsophisticated way we currently handle send priority in the SendPendingData loop for non-h3 applications, tho. I do think it's important that we have the ability to experiment with different send prioritization schemes for things that aren't h3 so as long as we are still working towards that, I'm good. (Restricting the public supported APIs in the interim is a good approach to ensuring we don't box ourselves into a corner)
Ok, I have asked upstream. It currently is not on the agenda. Best would be to have no SendGroups in the moment, but to make it in a way that we can extend it later, if sendgroups prove to be something worth to implement.
Edit: discussion with upstream is not final. But it will be wt only.
- added a commit that references this issue
on Sep 8, 2026
Currently, when calling
createBidirectionalStreamyou can specify apriority(same also for unidirectional stream):The W3C specification for webtransport defines a
sendGroupmechanism; see https://www.w3.org/TR/webtransport/#sendGroup.For me, this is not the most important mechanism (but I can not tell for others), but I just wanted to bring it to your attention (@jasnell) and ask if it is worth thinking about an implementation that aligns with this spec, as the workgroup has put much thought into it.
Currently, I think it is a very different approach.