Skip to content

fix: stop realtime heartbeat from stacking and crashing on closed socket#1587

Open
yashs33244 wants to merge 1 commit into
appwrite:mainfrom
yashs33244:fix/realtime-heartbeat-interval
Open

fix: stop realtime heartbeat from stacking and crashing on closed socket#1587
yashs33244 wants to merge 1 commit into
appwrite:mainfrom
yashs33244:fix/realtime-heartbeat-interval

Conversation

@yashs33244

Copy link
Copy Markdown

The realtime client cleared its heartbeat with clearTimeout, but the handle comes from setInterval, so it was never cancelled - a new interval stacked on every reconnect. The interval also called socket.send() with no readyState check, which throws INVALID_STATE_ERROR when the socket is CLOSING/CLOSED during a reconnect (background + network drop + foreground cycle).

Switched to clearInterval and only send the ping when the socket is OPEN, in both the web and react-native client templates.

Reported against the React Native SDK (which is generated from these templates): appwrite/sdk-for-react-native#101

…hing on closed socket

The realtime client cleared its heartbeat with clearTimeout even though the
handle comes from setInterval, so the interval was never cancelled and a new
one stacked on every reconnect. The interval body also called socket.send()
with no readyState check, which throws INVALID_STATE_ERROR when the socket is
CLOSING/CLOSED during a reconnect (e.g. after a background + network-drop +
foreground cycle).

Switch to clearInterval and only send the ping when the socket is OPEN, in
both the web and react-native client templates.
Copilot AI review requested due to automatic review settings June 15, 2026 19:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two related bugs in the realtime heartbeat logic present in both the web and React Native client templates: clearTimeout was being called on a setInterval handle (a no-op, so the interval stacked on every reconnect), and socket.send() was called without checking readyState, causing INVALID_STATE_ERROR when the socket was closing or closed.

  • clearTimeoutclearInterval: Correctly cancels the existing interval before scheduling a new one on reconnect, preventing unbounded stacking.
  • readyState === WebSocket.OPEN guard: Prevents send() from being called on a CLOSING/CLOSED socket, eliminating the crash reported in 🐛 Bug Report: INVALID_STATE_ERROR crash after background + network disconnect + foreground cycle sdk-for-react-native#101.
  • Residual leak: The heartbeat interval is still not cleared in the close handler's early-return path (intentional disconnect / policy-1008 error), leaving a harmless but unnecessary timer running until the next createHeartbeat call.

Confidence Score: 4/5

The two core changes are correct and address the reported crash; the only remaining gap is a minor timer leak on intentional disconnects that does no observable harm after this fix.

Both template files are updated consistently, the root causes (wrong clear function, missing readyState check) are properly addressed, and the changes are minimal and targeted. The one gap — the heartbeat interval not being cancelled when the socket is permanently closed — is silent after this PR because the new readyState guard prevents any actual send, making it a cleanup suggestion rather than a functional regression.

Both templates share the same minor gap in the close event handler's early-return path where the heartbeat interval is not stopped.

Important Files Changed

Filename Overview
templates/react-native/src/client.ts.twig Fixes heartbeat stacking (clearTimeout → clearInterval) and adds readyState guard; heartbeat interval is not cleared on intentional permanent disconnect.
templates/web/src/client.ts.twig Same fix as the React Native template — clearInterval + readyState guard applied consistently; same minor interval-leak on permanent close applies here too.

Comments Outside Diff (2)

  1. templates/react-native/src/client.ts.twig, line 360-370 (link)

    P2 The heartbeat interval is not cleared when the socket closes without reconnecting (the early-return branch). After this PR the interval fires harmlessly every 20 s (the readyState guard prevents any send), but it still accumulates as a leaked timer if the realtime object is reused across multiple connect/disconnect cycles with no subscription left.

  2. templates/web/src/client.ts.twig, line 551-561 (link)

    P2 Same orphaned-interval issue as in the React Native template: when the socket closes without reconnecting, the heartbeat interval is never cancelled. The readyState guard prevents any actual send, but the interval keeps ticking until createHeartbeat is called again on the next connection.

Reviews (1): Last reviewed commit: "fix(web,react-native): stop realtime hea..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants