Conversation
…e until resume() State in the Backpressure section and in the pause() JSDoc that a paused client reads nothing: it does not answer Ping frames and does not see a Close frame or the end of the connection. Name the Bun.serve idle timeout, and show a pong() heartbeat that keeps a long pause alive.
|
Warning Review limit reached
On-demand reviews are free for the next 4 days. After that, they cost $0.25 per reviewed file. Or wait 9 seconds for your next included review. View limit detailsLimit details: You’ve used all 10 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (2)
Comment |
|
Status: docs change, ready for review. How I reproduced the report, on 1.4.3 (Linux x64) and 1.4.3-canary.1+a8e4e9042 (Windows x64):
This PR changes CI on 3d835cc: no failure comes from this diff, which changes no compiled input.
|
|
Updated 2:13 PM PT - Sep 16th, 2026
❌ @robobun, your commit 3d835cc has 1 failures in
🧪 To try this PR locally: bunx bun-pr 42976That installs a local version of the PR into your bun-42976 --bun |
Problem
WebSocketthat stayspause()d longer than the server's idle timeout is dropped, and gets nocloseevent untilresume(). WithidleTimeout: 8the server closes at 8.0 s (1006, "WebSocket timed out from inactivity"). The client readsreadyState1 untilresume()at 24.0 s, then getsclose1006 "Connection ended".pause()means. The client stops reading, so it sees no Ping, Close frame or FIN. uSockets holds a paused socket's EOF untilresume()on purpose (packages/bun-usockets/src/loop.c:849), to keep unread data. Thewspackage on Node v26.3.0 does the same.pause()JSDoc and the "Backpressure" docs section do not say so. The docs example pauses with no bound.Fix
docs/runtime/http/websockets.mdx: say what a paused client does not do, name theBun.serveidle timeout, and show apong()heartbeat for a long pause.packages/bun-types/bun.d.ts: the same facts in thepause()JSDoc.Background
us_socket_pauseremoves the readable interest from the socket's poll. Writes still work.Bun.serveresets a WebSocket's idle timer on every frame it receives (packages/bun-uws/src/WebSocketContext.h:307). WithsendPings: trueit sends a Ping before the timeout, and the Pong resets the timer.Notes
Repro (from the report), 1.4.3 on Linux x64. Server:
Bun.servewithwebsocket.idleTimeout: 8, sends"hello"on open. Client:pause()inonmessage, probesreadyStateevery 4 s,resume()at 24 s.Node parity.
ws8.18.3 on Node v26.3.0, clientws.pause()on the first message, server pings at 1 s and 2 s and callsterminate()at 3 s:Statements in the new text, each run.
ws.close(1000, "bye")while the client is paused: clientreadyState1 at 2.0 s,close1000 "bye" right afterresume(). Same overwss://, and on Windows.ws.terminate(): clientreadyState1 at 2.0 s,close1006 right afterresume().send(),ping(),pong()work while pausedmessage,pingandponghandlers fire at 0.0 s for a paused client. Run overws://,wss://,wss://through anhttp://and anhttps://CONNECT proxy,ws://through anhttps://proxy, and on Windows.Bun.servecounts every frame as activityidleTimeout: 8, paused client callspong()every 3 s: no close on either side through 21 s, and the connection still works afterresume(). Without thepong()the server closes at 8.0 s.pong()on a closed socket does not throwpong(),ping()andsend()return normally inCLOSINGandCLOSED, so the timer in the snippet is safe if the socket closes first.The snippet, as written. A
Writablethat drains after 60 s stands in forfile.idleTimeout: 40, heartbeat30_000:The first docs example (no heartbeat), same setup:
Why
close"can wait" and not "waits". A connection reset is reported at once, also while paused. Asend()into a connection that the server already closed gets an RST back, and the client then dispatchesclose1006 without aresume()(seen at 12.0 s in a run where the server closed at 8.0 s).Types test.
test/integration/bun-types/bun-types.test.tsfails 10 of 21 tests, with the same diagnostics, with and without this change. Thebun-typesCI job on this PR fails the same way, and so do its last 25 runs on six unrelated branches. The diagnostics are missing@types/nodeexports (for exampleTextEncoderEncodeIntoResult,TLSSocket,KeyObject). #42230 tracks that break. An earlier version of this note said my environment could not install the fixture dependencies. That cause was wrong. This change cannot affect the job:bun.d.tsatmainand at this commit print identically with comments removed (TypeScript 6.0.2, 0 parse diagnostics).The RFC link resolves (HTTP 200) and the page has the
section-5.5.3anchor.