-
-
Notifications
You must be signed in to change notification settings - Fork 614
feat: use provided maxConcurrentStreams as multiplexing factor #4158
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
base: main
Are you sure you want to change the base?
feat: use provided maxConcurrentStreams as multiplexing factor #4158
Conversation
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.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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)
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.
Good work! Can you fix the tests?
Mark the client with "manual" max concurrent streams provided and use it to overwrite default "pipelining" behaviour with H2 multiplexing limits.
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.
lgtm, just minor comment
@@ -68,6 +69,10 @@ const getDefaultNodeMaxHeaderSize = http && | |||
const noop = () => {} | |||
|
|||
function getPipelining (client) { | |||
if (client[kHTTPContext]?.version === 'h2' && client[kMaxConcurrentStreamsManual]) { |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
This relates to...
Closes #4143.
Rationale
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 changepipelining
in order to achieve multiplexing over a H2 stream.Changes
Features
pipelining
.Bug Fixes
Breaking Changes and Deprecations
maxConcurrentStreams
themselves.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. ↩