undici icon indicating copy to clipboard operation
undici copied to clipboard

Default pipelining to maxConcurrentStreams with allowH2

Open slagiewka opened this issue 7 months ago • 4 comments
trafficstars

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

slagiewka avatar Apr 03 '25 09:04 slagiewka