Skip to content

fix: recover the streamed reply after Android background/resume#493

Open
X-15 wants to merge 1 commit into
cogwheel0:mainfrom
X-15:fix/android-resume-recover-completion
Open

fix: recover the streamed reply after Android background/resume#493
X-15 wants to merge 1 commit into
cogwheel0:mainfrom
X-15:fix/android-resume-recover-completion

Conversation

@X-15

@X-15 X-15 commented Jun 4, 2026

Copy link
Copy Markdown

Problem

On Android, backgrounding the app suspends the Flutter isolate and the OS tears down the TCP connection, but socket.io never processes the disconnect. On resume the socket is frequently a zombie (connected == true but dead):

  • nothing fires disconnect, so there is no auto-reconnect;
  • the connectivity-edge force-reconnect never triggers, because the network never actually went offline.

Since OpenWebUI delivers chat completions out-of-band over the socket and does not replay missed events, a reply that finishes while the app is backgrounded is lost — the user sees nothing until a full app restart.

Fix

socket_service.dart — resume reconnect

  • Force a fresh socket and emit a reconnect only on a genuine background→foreground transition (paused/hidden/detachedresumed). The transient inactive state (notification shade, app switcher, permission/system dialog, PiP) is treated as foreground, so a healthy socket is no longer torn down on every shade peek.
  • A re-entrancy guard prevents overlapping resume reconnects from spawning concurrent forced connects (which could orphan socket.io engines).

app_startup_providers.dart — resume re-fetch

  • On resume, re-fetch the currently open conversation from the server (the source of truth) so a reply that completed in the background appears immediately, independent of the socket state.
  • A stale-write guard ensures a slow fetch cannot overwrite a conversation the user switched to during the round-trip.

Notes

  • Behavior verified on a Samsung S23 (an aggressive foreground-service killer): backgrounding fully and returning recovers the missed reply; pulling the notification shade no longer churns the socket.
  • No new dependencies.

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown

Reviews (1): Last reviewed commit: "fix: recover the streamed reply after An..." | Re-trigger Greptile

Comment thread lib/core/services/socket_service.dart
@X-15 X-15 force-pushed the fix/android-resume-recover-completion branch from 6c3b8c8 to b425402 Compare June 4, 2026 03:37
On Android the OS suspends the isolate when the app is backgrounded and
tears down the TCP connection, but socket.io never processes the
disconnect. On resume the socket is often a zombie (connected == true but
dead): nothing fires 'disconnect', nothing auto-reconnects, and the
connectivity-edge force-reconnect never triggers because the network never
actually went offline. Since OpenWebUI streams completions out-of-band over
the socket and does not replay missed events, the in-flight reply is lost
until a full app restart.

Two parts:

- socket_service: only a real background->foreground transition
  (paused/hidden/detached -> resumed) forces a fresh socket and emits a
  reconnect so streaming recovery polls the server for the missed
  completion. The transient `inactive` state (notification shade, app
  switcher, permission/system dialog) is treated as foreground so it no
  longer tears down a healthy socket on every shade peek. A re-entrancy
  guard prevents overlapping resume reconnects from orphaning sockets.

- app_startup_providers: on resume, re-fetch the open conversation from
  the server (the source of truth) so a reply that finished in the
  background appears immediately, with a stale-write guard so a slow fetch
  cannot overwrite a conversation the user switched to in the meantime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant