fix: add WebSocket ping/pong to detect dead connections in log viewer
Without ping/pong, silently dropped connections (network loss, phone sleep) would leak goroutines and logger subscriptions until the OS-level TCP timeout (minutes). Now pings every 54s; if no pong within 60s the connection is closed and all resources (goroutines, subscriptions, client slots) are released. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d77106da2e
commit
efb6ec0d2e
1 changed files with 20 additions and 1 deletions
|
|
@ -210,6 +210,11 @@ type Handler struct {
|
|||
|
||||
const maxWSClients = 4
|
||||
|
||||
const (
|
||||
wsPongWait = 60 * time.Second
|
||||
wsPingPeriod = 54 * time.Second // must be less than wsPongWait
|
||||
)
|
||||
|
||||
type wsClient struct {
|
||||
conn *websocket.Conn
|
||||
}
|
||||
|
|
@ -936,6 +941,13 @@ func (h *Handler) wsLogs(w http.ResponseWriter, r *http.Request) {
|
|||
sub := logger.Subscribe(filter)
|
||||
defer logger.Unsubscribe(sub)
|
||||
|
||||
// Configure ping/pong to detect dead connections
|
||||
conn.SetReadDeadline(time.Now().Add(wsPongWait))
|
||||
conn.SetPongHandler(func(string) error {
|
||||
conn.SetReadDeadline(time.Now().Add(wsPongWait))
|
||||
return nil
|
||||
})
|
||||
|
||||
// Send initial data
|
||||
initial := logger.RecentLogs(minLevel, component, 50)
|
||||
if err := conn.WriteJSON(map[string]any{"type": "init", "entries": initial}); err != nil {
|
||||
|
|
@ -953,7 +965,10 @@ func (h *Handler) wsLogs(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}()
|
||||
|
||||
// Stream loop
|
||||
// Stream loop with periodic pings
|
||||
ticker := time.NewTicker(wsPingPeriod)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case entry, ok := <-sub.Ch:
|
||||
|
|
@ -965,6 +980,10 @@ func (h *Handler) wsLogs(w http.ResponseWriter, r *http.Request) {
|
|||
if err := conn.WriteJSON(map[string]any{"type": "entry", "entry": entry}); err != nil {
|
||||
return
|
||||
}
|
||||
case <-ticker.C:
|
||||
if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
||||
return
|
||||
}
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue