Skip to content

Fix: send connection-level WINDOW_UPDATE at session start #2971

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 4 commits into
base: master
Choose a base branch
from

Conversation

KoenRijpstra
Copy link

@KoenRijpstra KoenRijpstra commented Jun 27, 2025

Overview

@grpc/grpc-js previously opened every HTTP/2 connection with the RFC‑default 65 535‑byte connection window, then waited until after the first DATA frames were received before enlarging it. On fast, high‑volume streams this small initial window causes the sender (or any intermediate HTTP/2 proxy) to buffer excess data, creating avoidable latency.

This change immediately enlarges the connection‑level window as soon as the session is created when the application has requested a larger value via

'grpc-node.flow_control_window'

This aligns the Node implementation with other gRPC language stacks that send the larger window before any payload is transmitted.


Core change (single patch)

// createSession() — directly after http2.connect()
const defaultWin = http2.getDefaultSettings().initialWindowSize; // 65 535
const connWin = options["grpc-node.flow_control_window"] as number | undefined;

// Apply user‑requested window immediately so the first DATA burst is not throttled
if (connWin && connWin > defaultWin) {
  try {
    // Node ≥ 14.18
    (session as any).setLocalWindowSize(connWin);
  } catch {
    // Older Node fallback
    const delta = connWin - (session.state.localWindowSize ?? defaultWin);
    if (delta > 0) (session as any).incrementWindowSize(delta);
  }
}

No public API changes. Clients that do not set the option keep the existing behaviour.


Impact

Before After
Initial flow‑control Sender stalls after 65 KB Full requested window available at once
Latency under load Can grow as buffers back up Remains stable
Compatibility Behaviour now matches Go/C/C++/Rust gRPC

Works on Node 14 → 20 (fallback path covers older Node versions).


Changelog entry

### Fixed
* http2: enlarge connection‑level flow‑control window at session start when a larger
  'grpc-node.flow_control_window' is configured.

If the user sets `grpc-node.connection_flow_control_window` to a value
> 65 535 B, we now send a WINDOW_UPDATE (or setLocalWindowSize) right
after `http2.connect()` returns. This removes the 65 KB start-window
stall that caused large initial backlogs on high-throughput streams,
especially when an H2 proxy (e.g. HAProxy) sat between client and
server. Behaviour now matches Go/Rust gRPC; no API changes.
Copy link

linux-foundation-easycla bot commented Jun 27, 2025

CLA Signed


The committers listed above are authorized under a signed CLA.

@murgatroid99
Copy link
Member

The setLocalWindowSize documentation indicates that it should be called in the handler for the 'connect' or 'remoteSettings' event. There is already a 'remoteSettings' handler, so it should be moved there. This change should still work as intended because the session isn't used until after that event is handled anyway.

@KoenRijpstra
Copy link
Author

KoenRijpstra commented Jun 27, 2025

@murgatroid99

The setLocalWindowSize documentation indicates that it should be called in the handler for the 'connect' or 'remoteSettings' event. There is already a 'remoteSettings' handler, so it should be moved there. This change should still work as intended because the session isn't used until after that event is handled anyway.

I’ve moved it to remoteSettings, and it still works as expected 🚀. Mind giving it another review?

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.

2 participants