Skip to content

Commit 810d7c6

Browse files
committed
feat!: use maxConcurrentStreams as multiplexing factor
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.
1 parent 6ea61af commit 810d7c6

File tree

4 files changed

+9
-5
lines changed

4 files changed

+9
-5
lines changed

benchmarks/benchmark-http2.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const servername = 'agent1'
1515
const iterations = (parseInt(process.env.SAMPLES, 10) || 10) + 1
1616
const errorThreshold = parseInt(process.env.ERROR_THRESHOLD, 10) || 3
1717
const connections = parseInt(process.env.CONNECTIONS, 10) || 50
18-
const pipelining = parseInt(process.env.PIPELINING, 10) || 10
18+
const maxConcurrentStreams = parseInt(process.env.MULTIPLEXING, 10) || 10
1919
const parallelRequests = parseInt(process.env.PARALLEL, 10) || 100
2020
const headersTimeout = parseInt(process.env.HEADERS_TIMEOUT, 10) || 0
2121
const bodyTimeout = parseInt(process.env.BODY_TIMEOUT, 10) || 0
@@ -61,7 +61,7 @@ const http2NativeClient = http2.connect(httpsBaseOptions.url, {
6161
const Class = connections > 1 ? Pool : Client
6262
const dispatcher = new Class(httpsBaseOptions.url, {
6363
allowH2: true,
64-
pipelining,
64+
maxConcurrentStreams,
6565
connections,
6666
connect: {
6767
rejectUnauthorized: false,
@@ -73,7 +73,7 @@ const dispatcher = new Class(httpsBaseOptions.url, {
7373

7474
setGlobalDispatcher(new Agent({
7575
allowH2: true,
76-
pipelining,
76+
maxConcurrentStreams,
7777
connections,
7878
connect: {
7979
rejectUnauthorized: false,

docs/docs/api/Client.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Returns: `Client`
2424
* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `2e3` - A number of milliseconds subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 2 seconds.
2525
* **maxHeaderSize** `number | null` (optional) - Default: `--max-http-header-size` or `16384` - The maximum length of request headers in bytes. Defaults to Node.js' --max-http-header-size or 16KiB.
2626
* **maxResponseSize** `number | null` (optional) - Default: `-1` - The maximum length of response body in bytes. Set to `-1` to disable.
27-
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
27+
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections. Ineffective for H2 sessions.
2828
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
2929
* **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body.
3030
* **autoSelectFamily**: `boolean` (optional) - Default: depends on local Node version, on Node 18.13.0 and above is `false`. Enables a family autodetection algorithm that loosely implements section 5 of [RFC 8305](https://tools.ietf.org/html/rfc8305#section-5). See [here](https://nodejs.org/api/net.html#socketconnectoptions-connectlistener) for more details. This option is ignored if not supported by the current Node version.

lib/dispatcher/client.js

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ const getDefaultNodeMaxHeaderSize = http &&
6868
const noop = () => {}
6969

7070
function getPipelining (client) {
71+
if (client[kHTTPContext]?.version === 'h2') {
72+
return client[kMaxConcurrentStreams] ?? client[kHTTPContext]?.defaultPipelining ?? 100
73+
}
74+
7175
return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1
7276
}
7377

types/client.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export declare namespace Client {
5959
keepAliveTimeoutThreshold?: number;
6060
/** TODO */
6161
socketPath?: string;
62-
/** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Default: `1`. */
62+
/** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Ineffective for H2 sessions. Default: `1`. */
6363
pipelining?: number;
6464
/** @deprecated use the connect option instead */
6565
tls?: never;

0 commit comments

Comments
 (0)