feat: use provided maxConcurrentStreams as multiplexing factor#4158
feat: use provided maxConcurrentStreams as multiplexing factor#4158slagiewka wants to merge 1 commit intonodejs:mainfrom
Conversation
slagiewka
left a comment
There was a problem hiding this comment.
I didn't touch the H2CClient yet, but it might be addressed as well. Granted, this has lesser priority as it already defaults pipelining to be equal maxConcurrentStreams.
lib/dispatcher/client.js
Outdated
| if (client[kHTTPContext]?.version === 'h2') { | ||
| return client[kMaxConcurrentStreams] ?? client[kHTTPContext]?.defaultPipelining ?? 100 | ||
| } |
There was a problem hiding this comment.
What remains unclear to me is under which circumstances getPipelining can be called with a client that has no kHTTPContext present.
In any case, this tries to figure out whether we're using H2 and short circuit on that decision.
The statement below acts as a fallback but I'm almost 100% sure that client[kPipelining] always wins (is never nullish) since a client is always created with on in its constructor. However, the setter for pipelining COULD make it nullish (for some reason) and only then it would fall to the context's setting.
metcoder95
left a comment
There was a problem hiding this comment.
We are not yet preparing a new major version, so we will need to make it backwards compatible with a warning that states the change;
We can follow the path of putting maxCurrentStreams in higher order of priority compared to pipelining for h2, but still honor pipelining if maxConcurrentStreams is not passed so we keep do not introduce a breaking change (just yet)
mcollina
left a comment
There was a problem hiding this comment.
Good work! Can you fix the tests?
| const noop = () => {} | ||
|
|
||
| function getPipelining (client) { | ||
| if (client[kHTTPContext]?.version === 'h2' && client[kMaxConcurrentStreamsManual]) { |
There was a problem hiding this comment.
Let's just add a deprecation warning if maxConcurrentStreams is not set, and we should be good to go
There was a problem hiding this comment.
When would that happen? The symbol (which name I don't like yet 🙈 ) that I'm using is only set if maxConcurrentStreams is set (line 240).
Or your suggestion is to notify everyone using allowH2 but not setting it - therefore missing the benefit of multiplexing?
I'm also not sure WHEN that deprecation warning would happen. I assume that somewhere in Client constructor. Otherwise the noise would be significant.
There was a problem hiding this comment.
I was thinking to add it only when the kMaxConcurrentStreamsManual is set to false but pipeline was altered instead; so the warning states that in further major pipeline will not take the effect of maxConcurrentStreams
|
One comment from me: with the original change enabling 100 concurrent streams for the entire codebase might have uncovered some issues when multiplexing is in use. Tests might be indication of that. |
Haven't run the benchmarks yet (might do it Today); but what's have you see? |
It's actually not in benchmarks but in tests: Which is 100% reproducible for me when At first I thought that maybe there's something wrong with how "destroy" happens on a stream once request gets aborted and instead the session gets hit. But the error happens on the mock server in this test (trying to respond) - haven't looked yet into why that may happen with many streams vs a single stream. |
For H2 sessions pipelining is misleading and is a concept of HTTP/1.1. This makes use of `maxConcurrentStreams` parameter to be equivalent of what H2 calls multiplexing. It makes sure that clients do not have to change `pipelining` in order to achieve multiplexing over a H2 stream. Closes nodejs#4143.
a261269 to
bc5c5f6
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4158 +/- ##
==========================================
- Coverage 93.19% 93.18% -0.01%
==========================================
Files 109 109
Lines 34222 34229 +7
==========================================
+ Hits 31893 31897 +4
- Misses 2329 2332 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Hey @metcoder95 I've found multiple problems with these benchmarks in general:
As a bonus, the "native" pass will be in a disadvantage since it's always 1 connection (session). Maybe sticking to 1 connection/session for all of them and controlling number of streams would give every pass a fair playing ground.
I'm having doubts about such an explicit approach.
|


This relates to...
Closes #4143.
Rationale
For H2 sessions pipelining is misleading and is a concept of HTTP/1.1.
This makes use of
maxConcurrentStreamsparameter to be equivalent of what H2 calls multiplexing. It makes sure that clients do not have to changepipeliningin order to achieve multiplexing over a H2 stream.Changes
Features
pipelining.Bug Fixes
Breaking Changes and Deprecations
maxConcurrentStreamsthemselves.Status
Footnotes
This makes undici (non-fetch) results way closer to "native - http2" under a single connection. It is worth noting that any benchmarks running on 2+ connections are unfair to "native" as it has a single connection open. ↩