Skip to content

fix(mobile): probe socket liveness on resume instead of trusting session state - #4963

Open
Theremoteaidoc wants to merge 1 commit into
block:mainfrom
Theremoteaidoc:fix/mobile-resume-zombie-socket
Open

fix(mobile): probe socket liveness on resume instead of trusting session state#4963
Theremoteaidoc wants to merge 1 commit into
block:mainfrom
Theremoteaidoc:fix/mobile-resume-zombie-socket

Conversation

@Theremoteaidoc

Copy link
Copy Markdown

Fixes #4962

Problem

onAppResumed trusts state.status == SessionStatus.connected when the background stint was shorter than the grace window. After an iOS suspend the transport can be half-open (screen lock drops the network, NAT rebinds on interface switch; the frozen VM never ran the grace-disconnect timer and no close frame arrives), so the app resumes onto a zombie socket: live subscriptions are silent until the user force-kills the app.

Fix

On the early-return path, run a cheap liveness probe: a minimal REQ (kinds [39000], limit 1) that resolves on EOSE, with a 3s timeout (constructor-injectable for tests). On timeout or error, reconnect() — the existing replay-with-since-skew then delivers everything missed. A healthy socket answers EOSE in one round-trip and nothing else changes.

Tests

Two new cases alongside the existing resume tests, using a send-recording controlled socket:

  • resume within grace + probe answered with EOSE: same socket kept, still connected (preserves the existing short-background behavior);
  • resume within grace + probe never answered: reconnect fires (new socket, old disposed, reconnecting).

Authored with Claude Code on a self-hosted Buzz deployment where our operator hit this daily on iPhone; happy to adjust probe kind/timeout to maintainer preference.

🤖 Generated with Claude Code

https://claude.ai/code/session_0167FGVQ3hiePvK6V32HioqZ

…ion state

When the app resumes within the background grace window, onAppResumed
trusted state.status == connected and returned early. But the transport
can be half-open after even a brief background stint: iOS drops the
network on screen lock or rebinds NAT on a Wi-Fi/cellular switch, and no
close frame ever reaches the client. The session is then a zombie - live
subscriptions stay silent and the UI never updates until the user
force-kills the app.

Replace flag-trust with a cheap liveness probe on the early-return path:
a minimal REQ that resolves on EOSE (3s timeout, injectable for tests).
On timeout or error, reconnect - which already replays live
subscriptions with the since-skew.

Repro on device: open a channel on iOS, background the app briefly (or
lock the screen), have another client post to the channel, resume: the
message never renders; force-kill + reopen shows it. With the probe, the
dead transport is detected on resume and the reconnect replay delivers
the missed events.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167FGVQ3hiePvK6V32HioqZ
@Theremoteaidoc
Theremoteaidoc requested a review from a team as a code owner August 5, 2026 21:18
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.

mobile: messages stop arriving after brief background/screen-lock until app is force-killed (zombie socket on resume)

1 participant