Skip to content

sdk: recover reconnect on window focus and network return#5525

Open
DexterKoelson wants to merge 1 commit into
clockworklabs:masterfrom
DexterKoelson:fix/reconnect-on-resume
Open

sdk: recover reconnect on window focus and network return#5525
DexterKoelson wants to merge 1 commit into
clockworklabs:masterfrom
DexterKoelson:fix/reconnect-on-resume

Conversation

@DexterKoelson

Copy link
Copy Markdown
Contributor

Fixes: #5524

Description of Changes

Add visibilitychange, focus, online, and pageshow listeners to ConnectionManager (browser only). On resume, each retained connection is re-checked: a reconnect whose backoff timer stalled is fired immediately with the backoff reset, and a socket that died silently (readyState CLOSING/CLOSED with no onclose) is torn down and rebuilt.

Supporting changes:

  • WebSocketAdapter gains an optional readyState member; the decompress and test adapters
    implement it.
  • DbConnectionImpl gains a public isSocketClosed getter used by the liveness check.

Scope: foreground half-open connections are already reaped by the server keep-alive (15s ping, 30s idle timeout in client-api), so this covers only the background-to-foreground gap. No client heartbeat is added; the server ping/pong is a WebSocket control frame and is not visible to browser JS.

API and ABI breaking changes

None. WebSocketAdapter.readyState is added as an optional member, so existing custom adapters supplied through withWSFn stay valid without changes. DbConnectionImpl.isSocketClosed is additive, and the two built-in adapters implement readyState.

Expected complexity level and risk

The change is confined to the React connection manager and the websocket adapter interface. It reuses the existing rebuild path, so reconnect semantics are unchanged apart from being triggered on resume. Listeners are only registered when window / document exist, so Node and SSR are unaffected.

Testing

  • New unit tests in tests/connection_manager_liveness.test.ts cover resume-triggered
    reconnect, zombie-socket rebuild, backoff reset, and the no-op cases (healthy connection,
    intentional disconnect, tab still hidden). (FYI, the tests were totally vibe coded)
  • Existing connection_manager and reconnect suites still pass.
  • I have been doing development on my web based game with this fix locally for a few days, it's been solid and I haven't had a non-reconnect issue since.
  • Reviewer: in a real browser, background the tab for a few minutes, then refocus and confirm the client reconnects.

ConnectionManager only reconnects in response to ws.onclose/onerror plus a
setTimeout backoff. Across a backgrounded or frozen tab the close event can be
dropped while the event loop is suspended, and background timers are throttled
or paused, so a scheduled reconnect never resumes when the window regains focus
and the connection stays dead.

Register visibilitychange, focus, online, and pageshow listeners (browser only).
On resume, fire a stalled reconnect immediately with the backoff reset, and
rebuild any socket that died silently (readyState CLOSING/CLOSED with no
onclose). Adds WebSocketAdapter.readyState and DbConnectionImpl.isSocketClosed
for the liveness check.

Foreground half-open connections are already reaped by the server keep-alive
(15s ping, 30s idle timeout), so this covers only the background-to-foreground
gap.
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.

React auto-reconnect sometimes stops after the tab is backgrounded and does not resume on focus

1 participant