Skip to content

fix(realtime): prevent INVALID_STATE_ERROR crash in heartbeat#110

Closed
Shivay-98 wants to merge 1 commit into
appwrite:mainfrom
Shivay-98:fix-101-invalid-state-error-heartbeat-crash
Closed

fix(realtime): prevent INVALID_STATE_ERROR crash in heartbeat#110
Shivay-98 wants to merge 1 commit into
appwrite:mainfrom
Shivay-98:fix-101-invalid-state-error-heartbeat-crash

Conversation

@Shivay-98

Copy link
Copy Markdown

Summary

Fixes #101

  • Replace clearTimeout with clearInterval when resetting the Realtime heartbeat timer (it was created with setInterval, so previous intervals were never cleared and stacked on every reconnect)
  • Guard socket.send() with a readyState === WebSocket.OPEN check so heartbeat pings are not sent on closing/closed sockets during reconnect

This aligns createHeartbeat() in src/client.ts with the existing pattern in src/services/realtime.ts.

Test plan

  • Open app with an active Realtime subscription
  • Disconnect network, send app to background
  • Reconnect network and wait for connection to re-establish
  • Bring app back to foreground
  • Confirm no INVALID_STATE_ERROR crash and Realtime resumes normally

Use clearInterval instead of clearTimeout when resetting the heartbeat timer, and guard socket.send() with a readyState check so pings are only sent on an open WebSocket.

Fixes appwrite#101

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown

This library is auto-generated by the Appwrite SDK Generator, and does not accept pull requests directly. To learn more about how you can help us improve this SDK, please check the contributing guide.

@github-actions github-actions Bot closed this Jun 30, 2026
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a two-part heartbeat bug in src/client.ts: clearTimeout was incorrectly used to cancel a timer created with setInterval (meaning old intervals were never cleared and accumulated on every reconnect), and heartbeat pings were sent without checking readyState, causing INVALID_STATE_ERROR on closing/closed sockets. The fix aligns createHeartbeat() with the equivalent pattern already present in src/services/realtime.ts.

  • Replaces clearTimeout with clearInterval and resets this.realtime.heartbeat to undefined after clearing, preventing interval accumulation across reconnects.
  • Adds a readyState === WebSocket.OPEN guard around socket.send() so pings are silently skipped on sockets that are not yet open or are already closing.

Confidence Score: 4/5

The change is a targeted, correct bug fix with no regressions introduced to the happy path.

Both fixes (clearInterval and the readyState guard) are straightforward and correct. The only gap left is that the heartbeat interval is not explicitly stopped in the socket close handler, so the timer continues running (doing nothing) during each reconnect backoff window — this is a minor cleanup opportunity, not a functional defect.

No files require special attention; src/client.ts is the only changed file and the diff is small and focused.

Important Files Changed

Filename Overview
src/client.ts Fixes the heartbeat timer: replaces clearTimeout with clearInterval (matching the setInterval used to create it), resets the handle to undefined after clearing, and guards socket.send() behind a readyState === WebSocket.OPEN check. The close handler does not explicitly stop the heartbeat, but the new guard prevents crashes during the reconnect window.

Comments Outside Diff (1)

  1. src/client.ts, line 479-498 (link)

    P2 Heartbeat interval not stopped on socket close

    The close event handler does not call clearInterval on this.realtime.heartbeat before reconnecting. This means the old interval keeps firing (harmlessly, due to the new readyState guard) during the entire reconnect backoff window. In realtime.ts, the companion stopHeartbeat() is called in the close handler to release the interval immediately. Since createHeartbeat() clears the previous interval on socket re-open, this does not cause stacking or crashes, but it leaves a live timer running longer than necessary on every reconnect cycle.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "fix(realtime): prevent INVALID_STATE_ERR..." | 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.

🐛 Bug Report: INVALID_STATE_ERROR crash after background + network disconnect + foreground cycle

1 participant