From 862310c4c6a8f32fa97ecf7a9275cb08139355ec Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 18 Dec 2025 21:33:50 +0000 Subject: [PATCH] fix: AI Patrol frequency not obeying settings Fixes #858 The patrol interval setting was not being properly applied due to: 1. ReconfigurePatrol() was setting the deprecated QuickCheckInterval field instead of the preferred Interval field 2. SetConfig() was comparing raw field values instead of using GetInterval() to compare effective intervals, causing change detection to fail 3. The API response was missing interval_ms, preventing the frontend from displaying the correct interval Changes: - Update StartPatrol() and ReconfigurePatrol() to use the Interval field - Fix SetConfig() to use GetInterval() for interval comparison - Add IntervalMs to PatrolStatusResponse and include it in the API response --- internal/ai/patrol.go | 7 ++++--- internal/ai/service.go | 26 ++++++++++++-------------- internal/api/ai_handlers.go | 2 ++ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/internal/ai/patrol.go b/internal/ai/patrol.go index a0f22da..ac10f68 100644 --- a/internal/ai/patrol.go +++ b/internal/ai/patrol.go @@ -265,18 +265,19 @@ func NewPatrolService(aiService *Service, stateProvider StateProvider) *PatrolSe // SetConfig updates the patrol configuration func (p *PatrolService) SetConfig(cfg PatrolConfig) { p.mu.Lock() - oldInterval := p.config.QuickCheckInterval + oldInterval := p.config.GetInterval() p.config = cfg + newInterval := cfg.GetInterval() configCh := p.configChanged p.mu.Unlock() // Signal config change if patrol is running and interval changed - if configCh != nil && cfg.QuickCheckInterval != oldInterval { + if configCh != nil && newInterval != oldInterval { select { case configCh <- struct{}{}: log.Info(). Dur("old_interval", oldInterval). - Dur("new_interval", cfg.QuickCheckInterval). + Dur("new_interval", newInterval). Msg("Patrol interval updated, resetting ticker") default: // Channel full or not ready, config will be picked up on next cycle diff --git a/internal/ai/service.go b/internal/ai/service.go index ab32093..b3c9ca0 100644 --- a/internal/ai/service.go +++ b/internal/ai/service.go @@ -358,13 +358,12 @@ func (s *Service) StartPatrol(ctx context.Context) { // Configure patrol from AI config patrolCfg := PatrolConfig{ - Enabled: true, - QuickCheckInterval: cfg.GetPatrolInterval(), - DeepAnalysisInterval: 6 * time.Hour, - AnalyzeNodes: cfg.PatrolAnalyzeNodes, - AnalyzeGuests: cfg.PatrolAnalyzeGuests, - AnalyzeDocker: cfg.PatrolAnalyzeDocker, - AnalyzeStorage: cfg.PatrolAnalyzeStorage, + Enabled: true, + Interval: cfg.GetPatrolInterval(), + AnalyzeNodes: cfg.PatrolAnalyzeNodes, + AnalyzeGuests: cfg.PatrolAnalyzeGuests, + AnalyzeDocker: cfg.PatrolAnalyzeDocker, + AnalyzeStorage: cfg.PatrolAnalyzeStorage, } patrol.SetConfig(patrolCfg) patrol.Start(ctx) @@ -404,13 +403,12 @@ func (s *Service) ReconfigurePatrol() { // Update patrol configuration patrolCfg := PatrolConfig{ - Enabled: cfg.IsPatrolEnabled(), - QuickCheckInterval: cfg.GetPatrolInterval(), - DeepAnalysisInterval: 6 * time.Hour, - AnalyzeNodes: cfg.PatrolAnalyzeNodes, - AnalyzeGuests: cfg.PatrolAnalyzeGuests, - AnalyzeDocker: cfg.PatrolAnalyzeDocker, - AnalyzeStorage: cfg.PatrolAnalyzeStorage, + Enabled: cfg.IsPatrolEnabled(), + Interval: cfg.GetPatrolInterval(), + AnalyzeNodes: cfg.PatrolAnalyzeNodes, + AnalyzeGuests: cfg.PatrolAnalyzeGuests, + AnalyzeDocker: cfg.PatrolAnalyzeDocker, + AnalyzeStorage: cfg.PatrolAnalyzeStorage, } patrol.SetConfig(patrolCfg) diff --git a/internal/api/ai_handlers.go b/internal/api/ai_handlers.go index f323987..9d35ccb 100644 --- a/internal/api/ai_handlers.go +++ b/internal/api/ai_handlers.go @@ -1956,6 +1956,7 @@ type PatrolStatusResponse struct { ResourcesChecked int `json:"resources_checked"` FindingsCount int `json:"findings_count"` Healthy bool `json:"healthy"` + IntervalMs int64 `json:"interval_ms"` // Patrol interval in milliseconds Summary struct { Critical int `json:"critical"` Warning int `json:"warning"` @@ -1997,6 +1998,7 @@ func (h *AISettingsHandler) HandleGetPatrolStatus(w http.ResponseWriter, r *http ResourcesChecked: status.ResourcesChecked, FindingsCount: status.FindingsCount, Healthy: status.Healthy, + IntervalMs: status.IntervalMs, } response.Summary.Critical = summary.Critical response.Summary.Warning = summary.Warning