Skip to content

fix(websocket): apply WebSocketStream receive backpressure#5562

Open
mcollina wants to merge 1 commit into
mainfrom
fix/websocketstream-backpressure
Open

fix(websocket): apply WebSocketStream receive backpressure#5562
mcollina wants to merge 1 commit into
mainfrom
fix/websocketstream-backpressure

Conversation

@mcollina

Copy link
Copy Markdown
Member

This relates to...

Fixes #5503

Rationale

WebSocketStream continued reading from the transport after its readable queue reached its high-water mark. Slow consumers therefore accumulated an unbounded number of messages instead of propagating backpressure to the peer.

Changes

Features

N/A

Bug Fixes

  • Pause the socket until the readable stream pulls.
  • Pause again when desiredSize reaches zero.
  • Resume only when there is downstream demand and the frame parser is ready, while continuing to read during the closing handshake.
  • Mark the existing WebSocketStream receive-backpressure WPT as passing.

Breaking Changes and Deprecations

N/A

Status

Validation

  • npm run lint
  • npm run test:websocket
  • node test/web-platform-tests/wpt-runner.mjs run '/websockets/stream/tentative/backpressure-receive.any.html?wss' '/websockets/stream/tentative/backpressure-send.any.html?wss'

Signed-off-by: Matteo Collina <hello@matteocollina.com>
@mcollina
mcollina requested review from KhafraDev and tsctx and removed request for tsctx July 15, 2026 10:25
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.45%. Comparing base (6010668) to head (4a98281).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5562      +/-   ##
==========================================
+ Coverage   93.44%   93.45%   +0.01%     
==========================================
  Files         110      110              
  Lines       37434    37459      +25     
==========================================
+ Hits        34979    35007      +28     
+ Misses       2455     2452       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.


// 7. Apply backpressure to the WebSocket.
// TODO
// This is done when the socket becomes available.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is wrong and could possibly lead to dropped messages.

  • user does new WebSocketStream(...)
  • await ws.opened
  • sets up the ReadableStream idk, 10 seconds later

any messages between the connection opening and reading messages will get "dropped" (stream will pull them even if the user isn't)

start: (controller) => {
this.#readableStreamController = controller
},
pull: () => this.#resumeSocketIfNeeded(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

" // 5. Let pullAlgorithm be an action that pulls bytes from stream ."

#resumeSocketIfNeeded does not do that

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

doesn't it make sense to handle backpressure in the WHATWG stream instead of the node socket? This implementation doesn't look correct to me


// 4. Apply backpressure to the WebSocket.
if (this.#readableStreamController.desiredSize <= 0) {
this.#handler.socket.pause()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ditto wrt node socket vs whatwg stream.

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.

WebSocketStream: receive backpressure is not implemented — a slow consumer buffers every received message in memory

4 participants