Uh oh!
There was an error while loading. Please reload this page.
fix: clear pendingHeartbeatRef unconditionally in onConnOpen - #54
Open
g0rdonL wants to merge 1 commit into
Open
Conversation
onConnOpen() only cleared a stranded pendingHeartbeatRef when autoSendHeartbeat was true (inside the resetHeartbeat() call gated by that flag). Clients configured with autoSendHeartbeat: false — e.g. @supabase/realtime-js's RealtimeClient in worker: true mode, where heartbeats are driven by a Worker instead of the socket's own timer — never got that clear. Consequence: a pendingHeartbeatRef armed on one connection and left pending by a drop-with-beat-in-flight (network blip, sleep, server close) survives onto the next, healthy connection. That connection's first externally-driven heartbeat then sees the stale non-null ref, takes the timeout branch in heartbeatTimeout(), and force-closes the still-healthy socket with "heartbeat timeout" having sent zero frames. Fix: hoist the pendingHeartbeatRef/heartbeatSentAt clear out of the autoSendHeartbeat gate in onConnOpen() so it always runs on connection open, matching what resetHeartbeat() already does unconditionally for the autoSendHeartbeat: true path. Only the timer-(re)arming call stays gated, which is unaffected since worker-mode clients drive heartbeats externally. Added a regression test covering onConnOpen() with autoSendHeartbeat: false and a pre-armed stale ref. Full suite: 217/220 passing (3 pre-existing skips), eslint clean.
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 freeto 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.
Bug
onConnOpen()only clears a strandedpendingHeartbeatRefwhenautoSendHeartbeatis true (it happens inside theresetHeartbeat()call, which is itself gated on that flag). Clients configured withautoSendHeartbeat: false— notably@supabase/realtime-js'sRealtimeClientinworker: truemode, a normal production configuration where heartbeats are driven by a Worker instead of the socket's own timer — never get that clear.Consequence: a
pendingHeartbeatRefarmed on one connection and left pending by a drop-with-beat-in-flight (network blip, laptop sleep, server-side close) survives onto the next, healthy connection. That connection's first externally-driven heartbeat then sees the stale non-null ref, takes the timeout branch inheartbeatTimeout(), and force-closes the still-healthy socket with"heartbeat timeout"having sent zero frames.Filed upstream as supabase/supabase-js#2625 (realtime-js consumes this library and surfaces the bug there — repro included, verified there against the published
@supabase/realtime-js/@supabase/phoenixpackages before tracing it to this file).Fix
Hoist the
pendingHeartbeatRef/heartbeatSentAtclear out of theautoSendHeartbeatgate inonConnOpen()so it always runs on connection open — matching whatresetHeartbeat()already does unconditionally for theautoSendHeartbeat: truepath. Only the timer-(re)arming call stays gated, which is unaffected since worker-mode clients drive heartbeats externally.Verification
onConnOpen › clears a stale pendingHeartbeatRef even when autoSendHeartbeat is false) that fails against unfixedmain(confirmed) and passes with this change.npm test→ 217/220 passing (3 pre-existing skips), up from 216/219 before the new test.npm run lintclean.worker: truemode end-to-end through@supabase/realtime-js) against the published packages to confirm the observed behavior before tracing the root cause here.