From 07b4765b8df60afa16bebf1432b67e31ab6741fe Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 9 Jan 2026 21:47:36 +0000 Subject: [PATCH] fix: respect quiet hours for recovery notifications (#1068) Recovery notifications were bypassing the quiet hours check, causing users to receive recovery alerts during their configured quiet hours window even though the original "down" alerts were suppressed. - Add ShouldSuppressResolvedNotification() to alert manager - Check quiet hours before sending recovery notifications in monitor - Recovery notifications now follow same suppression rules as alerts --- internal/alerts/alerts.go | 23 +++++++++++++++++++++++ internal/monitoring/monitor.go | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/internal/alerts/alerts.go b/internal/alerts/alerts.go index 201ed0649..9aabead7d 100644 --- a/internal/alerts/alerts.go +++ b/internal/alerts/alerts.go @@ -2116,6 +2116,29 @@ func (m *Manager) shouldSuppressNotification(alert *Alert) (bool, string) { return false, "" } +// ShouldSuppressResolvedNotification checks if a recovery notification should be suppressed +// during quiet hours. Recovery notifications follow the same quiet hours rules as their +// corresponding alerts - if the original alert would have been suppressed, so is the recovery. +func (m *Manager) ShouldSuppressResolvedNotification(alert *Alert) bool { + if alert == nil { + return false + } + + m.mu.RLock() + defer m.mu.RUnlock() + + suppressed, reason := m.shouldSuppressNotification(alert) + if suppressed { + log.Debug(). + Str("alertID", alert.ID). + Str("type", alert.Type). + Str("level", string(alert.Level)). + Str("quietHoursRule", reason). + Msg("Recovery notification suppressed during quiet hours") + } + return suppressed +} + // shouldNotifyAfterCooldown checks if enough time has passed since the last notification // Returns true if notification should be sent, false if still in cooldown period func (m *Manager) shouldNotifyAfterCooldown(alert *Alert) bool { diff --git a/internal/monitoring/monitor.go b/internal/monitoring/monitor.go index ae44c5aee..a0edf1849 100644 --- a/internal/monitoring/monitor.go +++ b/internal/monitoring/monitor.go @@ -8131,6 +8131,10 @@ func (m *Monitor) handleAlertResolved(alertID string) { m.notificationMgr.CancelAlert(alertID) if m.notificationMgr.GetNotifyOnResolve() { if resolved := m.alertManager.GetResolvedAlert(alertID); resolved != nil { + // Check if recovery notification should be suppressed during quiet hours + if m.alertManager.ShouldSuppressResolvedNotification(resolved.Alert) { + return + } go m.notificationMgr.SendResolvedAlert(resolved) } }