Skip to content

feat!: use 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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

slagiewka
Copy link

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 change pipelining in order to achieve multiplexing over a H2 stream.

Changes

Features

  • Allow controlling multiplexing over a stream without increasing pipelining.

Bug Fixes

Breaking Changes and Deprecations

  • Change of default behaviour for H2 streams. Users should be aware that with this change, their connections will start using multiplexing if they have not enabled it explicitly already.

Status

Footnotes

  1. 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.

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.
Copy link
Author

@slagiewka slagiewka left a 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.

@@ -15,7 +15,7 @@ const servername = 'agent1'
const iterations = (parseInt(process.env.SAMPLES, 10) || 10) + 1
const errorThreshold = parseInt(process.env.ERROR_THRESHOLD, 10) || 3
const connections = parseInt(process.env.CONNECTIONS, 10) || 50
const pipelining = parseInt(process.env.PIPELINING, 10) || 10
const maxConcurrentStreams = parseInt(process.env.MULTIPLEXING, 10) || 10
Copy link
Author

Choose a reason for hiding this comment

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

Either this or:

Suggested change
const maxConcurrentStreams = parseInt(process.env.MULTIPLEXING, 10) || 10
const maxConcurrentStreams = parseInt(process.env.MAX_CONCURRENT_STREAMS, 10) || 10

Unless you would prefer re-using the same semantic across benchmarks and keep "pipelining" here.

Comment on lines +71 to +73
if (client[kHTTPContext]?.version === 'h2') {
return client[kMaxConcurrentStreams] ?? client[kHTTPContext]?.defaultPipelining ?? 100
}
Copy link
Author

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.

@slagiewka slagiewka marked this pull request as ready for review April 13, 2025 06:55
Copy link
Member

@metcoder95 metcoder95 left a 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)

Copy link
Member

@mcollina mcollina left a 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?

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.

Default pipelining to maxConcurrentStreams with allowH2
3 participants