Fixed heap out of memory on network issues - #39
Conversation
Heap out of memory error happened, because WebSocket instance was not terminated when establishing new one, leading to massive spike in memory on network errors.
I could seperate it into two commits right?
|
Review: |
|
I think it's because it doesn't reconnect old socket, but calls new connect function, in which new socket is initialized, so I just deleted the old one manually not relying on GC and it worked, and this solution doesn't cap reconnect time, because we know time is money. |
|
Thanks for clarifying the root cause — that's exactly right. The orphaned sockets survive GC because the |
|
To be honest, I don't know TS at all. I'm JS developer. I kinda doesn't understand types at all. |
|
No worries — the TypeScript part doesn't matter here, the crash is a plain JavaScript runtime problem. |
|
Okey, I think solution could be hold on subscribe, and handle it on connect. |
|
Maybe even a quite bigger rework of whole think... User trough subscribe / unsubscribe regulates set of subscription messages, that are fired on moment called and also |
Handled case where `this.ws` is null.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.
Reviewed by Cursor Bugbot for commit 34610bf. Configure here.
| if (this.ws.readyState !== WebSocket.OPEN) { | ||
| return console.warn("Socket not open. Ready state is:", this.ws.readyState); | ||
| } | ||
|
|
There was a problem hiding this comment.
Stale handler kills new socket
High Severity
In onClose and onError, teardown uses this.ws instead of the socket that raised the event. After one handler sets this.ws to null and connect() assigns a new instance, a late close/error from the previous socket can terminate the active connection and trigger another reconnect.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 34610bf. Configure here.
| console.error("error", err); | ||
| this.notifyStatusChange(ConnectionStatus.DISCONNECTED); | ||
| if (this.ws) { | ||
| this.ws.removeAllListeners(); |
There was a problem hiding this comment.
Browser incompatible listener cleanup
High Severity
New teardown calls removeAllListeners on this.ws, but isomorphic-ws uses the native browser WebSocket, which has no such method. On network errors the handler throws before terminate, nulling, or reconnect run, so orphaned sockets and the heap growth can persist in browser builds.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 34610bf. Configure here.
Handled case when disconnect is called on non-existing socket.
|
That's the right direction — it's called a subscription store and it's how production WebSocket clients handle reconnects. Here's how it maps to this codebase concretely. |


Heap out of memory error happened, because WebSocket instance was not terminated when establishing new one, leading to massive spike in memory on network errors.
Note
Medium Risk
Changes core connection lifecycle and reconnect behavior; incorrect cleanup could drop subscriptions or cause double-reconnect edge cases, but the fix is narrowly scoped to teardown and guards.
Overview
Fixes heap out-of-memory when network failures trigger repeated reconnects by fully tearing down the previous WebSocket before opening a new one.
On error and close, the client now removes listeners, calls
terminate(), and setsthis.wstonullbeforeautoReconnectrunsconnect()again. Error handling also emitsDISCONNECTEDvianotifyStatusChange. Ping/pong, disconnect, subscribe, and unsubscribe guard against a missing socket so stale timers or API calls cannot touch a dead instance.Reviewed by Cursor Bugbot for commit 3180948. Bugbot is set up for automated code reviews on this repo. Configure here.