From 35528332fd8c628c628a42c9b1d179ef6de0d722 Mon Sep 17 00:00:00 2001 From: henrygd Date: Wed, 25 Mar 2026 23:44:29 -0400 Subject: [PATCH] hub: fix possible nil pointer panic in realtime worker --- internal/hub/systems/system_realtime.go | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/internal/hub/systems/system_realtime.go b/internal/hub/systems/system_realtime.go index 4b8998ae..6c27d0bd 100644 --- a/internal/hub/systems/system_realtime.go +++ b/internal/hub/systems/system_realtime.go @@ -19,7 +19,6 @@ type subscriptionInfo struct { var ( activeSubscriptions = make(map[string]*subscriptionInfo) workerRunning bool - realtimeTicker *time.Ticker tickerStopChan chan struct{} realtimeMutex sync.Mutex ) @@ -70,7 +69,7 @@ func (sm *SystemManager) onRealtimeSubscribeRequest(e *core.RealtimeSubscribeReq } // onRealtimeSubscriptionAdded initializes or starts the realtime worker when the first subscription is added. -// It ensures only one worker runs at a time and creates the ticker for periodic data fetching. +// It ensures only one worker runs at a time. func (sm *SystemManager) onRealtimeSubscriptionAdded() { realtimeMutex.Lock() defer realtimeMutex.Unlock() @@ -82,11 +81,6 @@ func (sm *SystemManager) onRealtimeSubscriptionAdded() { tickerStopChan = make(chan struct{}) go sm.startRealtimeWorker() } - - // If no ticker exists, create one - if realtimeTicker == nil { - realtimeTicker = time.NewTicker(1 * time.Second) - } } // checkSubscriptions stops the realtime worker when there are no active subscriptions. @@ -107,11 +101,6 @@ func (sm *SystemManager) checkSubscriptions() { } } - if realtimeTicker != nil { - realtimeTicker.Stop() - realtimeTicker = nil - } - // Mark worker as stopped (will be reset when next subscription comes in) workerRunning = false } @@ -135,17 +124,16 @@ func (sm *SystemManager) removeRealtimeSubscription(subscription string, options // It continuously fetches system data and broadcasts it to subscribed clients via WebSocket. func (sm *SystemManager) startRealtimeWorker() { sm.fetchRealtimeDataAndNotify() + tick := time.Tick(1 * time.Second) for { select { case <-tickerStopChan: return - case <-realtimeTicker.C: - // Check if ticker is still valid (might have been stopped) - if realtimeTicker == nil || len(activeSubscriptions) == 0 { + case <-tick: + if len(activeSubscriptions) == 0 { return } - // slog.Debug("activeSubscriptions", "count", len(activeSubscriptions)) sm.fetchRealtimeDataAndNotify() } }