#8524·multica

[Bug]: Realtime updates silently stop after WebSocket becomes half-open

Author: muchen-dgCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbug

Deployment type

self-host

Area

Web app

What happened?

The realtime WebSocket connection can become half-open while the web app keeps showing stale data.

When this happens, readyState stays OPEN and onclose never fires, so the client's reconnect logic never runs — the UI looks live but has silently stopped receiving events. Refreshing the page is the only way to recover.

A socket enters this state after:

  • a NAT gateway / proxy silently drops an idle connection,
  • the OS sleeps and wakes up,
  • the network path changes (Wi-Fi ↔ VPN ↔ hotspot).

In all of these cases the browser still believes the connection is healthy: the OS-level TCP state and the protocol-level ping/pong are invisible to JavaScript, and no close frame ever arrives. Application code therefore has no signal that the connection died, and WSClient (packages/core/api/ws-client.ts) keeps a socket that will never deliver another frame.

The server already implements an app-level ping/pong handler ({"type":"ping"} → {"type":"pong"} in server/internal/realtime/hub.go), but the web client never uses it as a health signal.

I have a fix for this and will open a PR shortly.

Steps to reproduce

  1. Open the web app and log in; wait for the realtime WebSocket to connect.
  2. Force the connection into a half-open state, e.g.:
    • put the OS to sleep and wake it a few minutes later, or
    • switch networks (Wi-Fi → VPN or hotspot), or
    • kill the API process abruptly (kill -9) behind a network path that swallows the RST/close frame.
  3. From another session/client, update any issue (comment, status change, agent activity).
  4. Observe: the original tab never receives the update, no reconnect is attempted, and the UI keeps showing stale data. In DevTools, readyState is still OPEN and no WS close event fires.

Screenshots (optional)

No response

Additional context (optional)

bash