undici
undici copied to clipboard
Default pipelining to maxConcurrentStreams with allowH2
Bug Description
The recent H2CClient work (#4118) does it well. If pipelining is not set, it defaults to maxConcurrentStreams which makes sense. This however, is not a case when a regular Client (or its descendent Agent) is in use.
Being on a HTTP/2 connection is still limited to either the default (1) or requires manual setup. Manual setup is inconvenient and confusing. Pipelining is a HTTP/1.1 concept.
Docs say nothing about adjust pipelining when using HTTP/2 multiplexing and actually link to the HTTP/1.1 RFC under pipelining.
Reproducible By
sever.js
import { fetch, Agent, setGlobalDispatcher, interceptors } from "undici";
import { createServer } from "node:http";
import { once } from "node:events";
setGlobalDispatcher(
new Agent({
allowH2: true,
connections: 10,
//pipelining: 100,
}).compose([interceptors.dns(), interceptors.retry()]),
);
const server = createServer((req, res) => {
fetch("https://my-https2-server.com", {
signal: AbortSignal.timeout(1_000),
})
.then((result) => {
return Array.fromAsync(result.body);
})
.then(() => {
res.end("");
})
.catch((err) => {
res.writeHead(500);
res.end("internal server error");
});
}).listen("3000");
await once(server, "listening");
console.log("server started on port 3000");
Then run the server:
node index.js
And load test it. Run the same with and without pipelining set.
hey -n 15000 -c 100 -q 300 -t "1" http://localhost:3000
Expected Behavior
Same performance with or without pipelining set.
Environment
Node 23, macOS 15.3, but it's not platform related, it seems.
Additional context
Should #2750 make HTTP/2 on by default, users will not benefit from HTTP/2 at all - it might behave pretty much the same as HTTP/1.1 connections with keep-alive + some TLS overhead...