Harden WebSocket Lifecycle, Reconnection Backoff, and Message Deserialization in Real-Time Data Client - #49
Open
mozluk wants to merge 2 commits into
Open
Harden WebSocket Lifecycle, Reconnection Backoff, and Message Deserialization in Real-Time Data Client#49mozluk wants to merge 2 commits into
mozluk wants to merge 2 commits into
Conversation
…lization in Real-Time Data Client
### Description
This pull request addresses reliability, resource lifecycle, and payload parsing findings identified in `real-time-data-client` during the workspace audit[cite: 8]. Previously, the client suffered from unhandled disconnections, unconstrained reconnection loops without backoff or jitter, platform-incompatible keepalive handlers, and unvalidated message payload deserialization[cite: 8]. This PR introduces full exponential backoff with jitter, decouples socket event listeners cleanly upon teardown, implements a cross-platform keepalive loop, and validates message shapes safely[cite: 8].
### Key Changes & Remediations
#### 1. Reconnection Resilience & Backoff Logic (`src/client.ts`)
* **Exponential Backoff with Full Jitter:** Replaced immediate zero-delay reconnect storms with an exponential backoff schedule bounded by `DEFAULT_MAX_RECONNECT_DELAY` (30s)[cite: 8]. Full jitter (`Math.random() * exponentialDelay`) prevents thundering-herd reconnect storms against the live data cluster.
* **Single Reconnect Timer:** Unified `onError` and `onClose` dispatch into a single idempotent `scheduleReconnect()` call, preventing concurrent duplicate socket spawns upon network drops.
#### 2. Resource Lifecycle & Teardown Cleanliness (`src/client.ts`)
* **Clean Socket Teardown:** Added `teardownSocket()` to nullify event listeners (`onopen`, `onmessage`, `onclose`, `onerror`) prior to closing the socket, preventing orphaned sockets from firing handlers or queueing redundant reconnects.
* **Cross-Platform Keepalive:** Replaced non-standard `ws.pong` handler bindings with a self-rescheduling timer (`startKeepalive`) that sends periodic `"ping"` text frames uniformly across Node.js and browser environments.
#### 3. Configuration & Payload Validation (`src/client.ts`)
* **Fail-Safe Construction:** Replaced unsafe non-null assertions with default arguments (`args = {}`) and nullish coalescing (`??`), ensuring `new RealTimeDataClient()` runs without runtime `TypeError` while honoring `autoReconnect: false`.
* **Bounded Ping Intervals:** Enforced finite, strictly positive millisecond checks on `pingInterval`.
* **Safe Message Parsing:** Eliminated fragile substring searching for `"payload"`. Incoming frames are now parsed with `JSON.parse` inside a try/catch and validated against the `isMessage` guard to discard malformed payloads gracefully without terminating the connection.
### How to Review
1. **Backoff Schedule:** Review `scheduleReconnect()` to verify the exponential backoff calculation and jitter bounds.
2. **Socket Teardown:** Check `teardownSocket()` and `connect()` to confirm old sockets are detached and closed before a new connection is instantiated.
3. **Keepalive Flow:** Inspect `startKeepalive()` to confirm periodic ping execution without platform-specific `pong` assignments.
4. **Message Guards:** Inspect `onMessage()` and `isMessage()` to ensure non-conforming JSON payloads do not throw unhandled exceptions.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Reviewed by Cursor Bugbot for commit c82563c. Configure here.
Author
|
Good catch. The manual mutation We have removed the mutation, made |
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.

Description
This pull request addresses reliability, resource lifecycle, and payload parsing findings identified in
real-time-data-clientduring the workspace audit[cite: 8]. Previously, the client suffered from unhandled disconnections, unconstrained reconnection loops without backoff or jitter, platform-incompatible keepalive handlers, and unvalidated message payload deserialization[cite: 8]. This PR introduces full exponential backoff with jitter, decouples socket event listeners cleanly upon teardown, implements a cross-platform keepalive loop, and validates message shapes safely[cite: 8].Key Changes & Remediations
1. Reconnection Resilience & Backoff Logic (
src/client.ts)DEFAULT_MAX_RECONNECT_DELAY(30s)[cite: 8]. Full jitter (Math.random() * exponentialDelay) prevents thundering-herd reconnect storms against the live data cluster.onErrorandonClosedispatch into a single idempotentscheduleReconnect()call, preventing concurrent duplicate socket spawns upon network drops.2. Resource Lifecycle & Teardown Cleanliness (
src/client.ts)teardownSocket()to nullify event listeners (onopen,onmessage,onclose,onerror) prior to closing the socket, preventing orphaned sockets from firing handlers or queueing redundant reconnects.ws.ponghandler bindings with a self-rescheduling timer (startKeepalive) that sends periodic"ping"text frames uniformly across Node.js and browser environments.3. Configuration & Payload Validation (
src/client.ts)args = {}) and nullish coalescing (??), ensuringnew RealTimeDataClient()runs without runtimeTypeErrorwhile honoringautoReconnect: false.pingInterval."payload". Incoming frames are now parsed withJSON.parseinside a try/catch and validated against theisMessageguard to discard malformed payloads gracefully without terminating the connection.How to Review
scheduleReconnect()to verify the exponential backoff calculation and jitter bounds.teardownSocket()andconnect()to confirm old sockets are detached and closed before a new connection is instantiated.startKeepalive()to confirm periodic ping execution without platform-specificpongassignments.onMessage()andisMessage()to ensure non-conforming JSON payloads do not throw unhandled exceptions.Note
Medium Risk
Touches core live connection behavior (reconnect timing, message filtering, and subscribe/send semantics), so consumers may see different delivery or retry patterns even though the changes fix known bugs.
Overview
Hardens
RealTimeDataClientWebSocket reliability, lifecycle, and inbound message handling insrc/client.ts.Reconnection no longer fires immediate duplicate connects from
onerror/onclose: a singlescheduleReconnect()applies exponential backoff with full jitter (configurablereconnectBaseDelay/maxReconnectDelay), resets on successful open, and respectsdisconnect()viaclosedByCaller.connect()tears down prior sockets (handler detach + close) before opening a new one.Keepalive is a cross-platform timer loop sending
"ping"text frames instead of the brokenws.pongassignment. Constructor defaults fixnew RealTimeDataClient()andautoReconnect: false;pingIntervalis validated as a positive finite value.Inbound frames are parsed safely (
try/catch+isMessage), ping/pong strings are ignored, and sends go throughrawSend(no Node-only send callbacks).subscribe/unsubscribereturn booleans and no longer force-close the socket on send failure.Reviewed by Cursor Bugbot for commit f16d572. Bugbot is set up for automated code reviews on this repo. Configure here.