Files
Laan Tungir 14e0dc5b7c Fix permanent zombie relay connections: detect dead transport in check_connection_health
When a relay closes the TCP connection without a clean WebSocket CLOSE
frame, the ws client's cached state remains NOSTR_WS_CONNECTED forever
(it only transitions on a clean close). Previously:

- nostr_ws_ping() send failures were silently ignored (return code
  unchecked), so the pool never learned the transport was dead
- the pong-timeout branch marked the relay DISCONNECTED but left the
  stale ws_client alive, so ensure_relay_connection() short-circuited
  on the cached CONNECTED state and never reconnected

Result: a single relay-side disconnect left the pool with zero live
sockets indefinitely while still reporting all relays connected —
all publishes dropped and all inbound events silently missed.

Fix: on ping-send failure or pong timeout, close and destroy the stale
ws client (ws_client = NULL) and mark the relay DISCONNECTED so the
reconnect logic performs a fresh connect. Recovery now takes one ping
interval + pong timeout + backoff (~1-2 min) instead of forever.

Observed in production on a didactyl agent: relays dropped the
connection at 00:08 UTC; the agent ignored all inbound DMs for 13+
hours while /api/status reported 3/3 connected.
2026-08-27 07:00:41 -04:00
..
2025-09-05 13:42:03 -04:00