Repository navigation
fix(sse): add a protocol-level ping/pong heartbeat to LiveWS - #10782
Merged
diegosouzapw merged 1 commit intoAug 20, 2026
Merged
diegosouzapw merged 1 commit into
diegosouzapw merged 1 commit into
Conversation
startHeartbeat() only refreshed a client's liveness on inbound application messages (diegosouzapw#10452), evicting a read-only subscriber that never sends anything. Send a protocol-level ping (RFC 6455 5.5.2) on each tick; conformant clients answer with a pong control frame automatically, refreshed in a new ws.on("pong") handler. A socket that stopped reading still goes unanswered and is reaped as before, so diegosouzapw#10452's protection is unchanged. The application-level pong is kept for clients that still rely on it. Extended the integration test with a third connection mode covering both properties.
maxmad64bis
force-pushed
the
fix/ws-heartbeat-ping-pong
branch
from
August 19, 2026 22:02
2d54a97 to
856c292
Compare
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…uzapw#10782) Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
startHeartbeat()only refreshes a client's liveness on inbound application messages. That wasdeliberate (fix(dashboard): send periodic WS heartbeat pings to stop live-dashboard reconnect churn #10452): renewing it on the server's own outbound pong would keep a half-open socket
alive indefinitely. But it also evicts a legitimate read-only subscriber — any dashboard watching
a live feed without interacting — after
HEARTBEAT_TIMEOUT_MS.pong control frame automatically, refreshed in a new
ws.on("pong")handler. A socket thatstopped reading frames still does not answer and is reaped exactly as before, so fix(dashboard): send periodic WS heartbeat pings to stop live-dashboard reconnect churn #10452's
protection is unchanged. The application-level pong is kept for clients that still rely on it.
Related Issues
Validation
tests/integration/live-ws-heartbeat-keepalive.test.tsagainst a real spawned server,npm run test:vitest(368/368)npm run lintTests Added Or Updated
tests/integration/live-ws-heartbeat-keepalive.test.tsThe existing #10452 test gains a third connection mode, so both properties are proven together: a
socket that stopped reading frames is still reaped, and a quiet-but-alive subscriber survives.
Coverage Notes
src/server/ws/liveServer.tsgains two statements — the ping call and the pong handler. Both areexercised by the integration test above against a real server process, which is the only layer
where a protocol-level control-frame round trip can be observed.
Reviewer Notes
ws's private_socket. Thereis no public API to model a half-open socket, and
terminate()would model a close instead. Itfails loudly if
wsever changes that internal.log rather than
readyState.HEARTBEAT_TIMEOUT_MS. It reuses the harness and timing ofthe already-merged fix(dashboard): send periodic WS heartbeat pings to stop live-dashboard reconnect churn #10452 test and adds no wall-clock cost — the three clients connect in
parallel before the single wait.