Fix early reminder notifications and lost recovery notifications

- AlertState.update() now resets last_notification when the alert level
  changes, so a WARNING→CRITICAL escalation restarts the reminder interval
  rather than inheriting a nearly-expired timer.
- _dispatch_to_channel() bypasses min_level for RECOVER, so recovery
  notifications are delivered even after a server restart when
  _alerted_channels is empty and the fallback dispatch path is used.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 18:11:22 +02:00
parent f61f7aebc2
commit afd5060f59
2 changed files with 15 additions and 7 deletions
+10 -3
View File
@@ -385,11 +385,18 @@ _DRIVERS = {
def _dispatch_to_channel(channel_name: str, channel_cfg: dict, notif: Notification) -> bool: def _dispatch_to_channel(channel_name: str, channel_cfg: dict, notif: Notification) -> bool:
"""Send *notif* to a single named channel, honouring min_level.""" """Send *notif* to a single named channel, honouring min_level.
RECOVER always bypasses min_level — a recovery is always relevant if the
channel was configured for any alerting (handles the restart-then-recover case
where _alerted_channels is empty and we fall through to the normal loop).
"""
level = notif.level.upper()
if level != "RECOVER":
min_level = channel_cfg.get("min_level", "WARNING").upper() min_level = channel_cfg.get("min_level", "WARNING").upper()
if _level_value(notif.level) < _level_value(min_level): if _level_value(level) < _level_value(min_level):
logger.debug( logger.debug(
"channel '%s': skipping level %s (min_level=%s)", channel_name, notif.level, min_level "channel '%s': skipping level %s (min_level=%s)", channel_name, level, min_level
) )
return True # not an error — filtered intentionally return True # not an error — filtered intentionally
+1
View File
@@ -105,6 +105,7 @@ class AlertState:
self.level = level self.level = level
self.since = now self.since = now
self.notification_count = 0 self.notification_count = 0
self.last_notification = None # restart reminder interval on level change
# Reset acknowledgment on state change # Reset acknowledgment on state change
if level != AlertLevel.OK: if level != AlertLevel.OK:
# Only reset if changing to a different alert level # Only reset if changing to a different alert level