Skip to content

Commit 0949fc0

Browse files
fix(realtime): terminate web worker on disconnect to prevent memory leak
Web Workers were created in _startWorkerHeartbeat() but never terminated in _teardownConnection(), causing memory accumulation with each disconnect/reconnect cycle. This fix adds a _terminateWorker() private method that properly terminates the Web Worker and clears the reference, then calls it during connection teardown. Fixes #1902
1 parent 8d1e0c5 commit 0949fc0

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

packages/core/realtime-js/src/RealtimeClient.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ export default class RealtimeClient {
645645
this.conn = null
646646
}
647647
this._clearAllTimers()
648+
this._terminateWorker()
648649
this.channels.forEach((channel) => channel.teardown())
649650
}
650651

@@ -710,6 +711,18 @@ export default class RealtimeClient {
710711
interval: this.heartbeatIntervalMs,
711712
})
712713
}
714+
715+
/**
716+
* Terminate the Web Worker and clear the reference
717+
* @internal
718+
*/
719+
private _terminateWorker(): void {
720+
if (this.workerRef) {
721+
this.log('worker', 'terminating worker')
722+
this.workerRef.terminate()
723+
this.workerRef = undefined
724+
}
725+
}
713726
/** @internal */
714727
private _onConnClose(event: any) {
715728
this._setConnectionState('disconnected')

packages/core/realtime-js/test/RealtimeClient.worker.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,27 @@ test('creates worker with blob URL when no workerUrl provided', () => {
9898
global.URL.createObjectURL = originalCreateObjectURL
9999
}
100100
})
101+
102+
test('terminates worker on disconnect', () => {
103+
// Establish connection first
104+
client.connect()
105+
106+
// Trigger worker creation
107+
client._onConnOpen()
108+
109+
// Verify worker was created
110+
assert.ok(client.workerRef)
111+
const worker = client.workerRef
112+
113+
// Spy on worker terminate method
114+
const terminateSpy = vi.spyOn(worker, 'terminate')
115+
116+
// Disconnect the client
117+
client.disconnect()
118+
119+
// Verify worker was terminated
120+
expect(terminateSpy).toHaveBeenCalled()
121+
122+
// Verify workerRef was cleared
123+
assert.equal(client.workerRef, undefined)
124+
})

0 commit comments

Comments
 (0)