Skip to content

Commit 9028a72

Browse files
committed
fix: first server alert suppressed within 5min of boot; deflake mute-expiry test
CI (running in a fresh UTC VM) surfaced two latent issues the local Europe/London + long-uptime environment was hiding: 1. UnraidSystemMonitor._rate_limited_alert used a sentinel of 0 for 'never alerted'. time.monotonic() is seconds-since-boot, so on a freshly-booted host (monotonic < _ALERT_COOLDOWN=300) the first server alert (CPU temp / memory / CPU usage) was wrongly suppressed for the first ~5 minutes of uptime — exactly when a hot reboot would most need it. Default to -inf so the first alert always fires. Reproduced at 5s simulated uptime: 85C alert suppressed before fix. 2. test_same_day asserted 'tomorrow' not in a now+1h mute expiry, which is flaky in the last hour before midnight. Pin 'now' to midday. Verified: full suite 1065 passed under TZ=UTC and TZ=Europe/London; ruff + mypy clean.
1 parent 5709339 commit 9028a72

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

src/unraid/monitors/system_monitor.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,11 @@ async def check_once(self) -> dict[str, Any] | None:
141141
async def _rate_limited_alert(self, key: str, **kwargs: Any) -> None:
142142
"""Send an alert only if cooldown has elapsed for this key."""
143143
now = time.monotonic()
144-
last = self._last_alert_times.get(key, 0)
144+
# Default to -inf (not 0) so the first alert always fires: on a
145+
# freshly-booted host time.monotonic() can be < _ALERT_COOLDOWN, and a
146+
# sentinel of 0 would wrongly suppress the very first alert within the
147+
# first few minutes of uptime.
148+
last = self._last_alert_times.get(key, float("-inf"))
145149
if now - last < _ALERT_COOLDOWN:
146150
logger.debug(f"Suppressing duplicate {key} alert (cooldown)")
147151
return

tests/test_formatting_utils.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,17 @@ class TestFormatMuteExpiry:
227227
"""Tests for format_mute_expiry."""
228228

229229
def test_same_day(self):
230+
from unittest.mock import patch
230231
from zoneinfo import ZoneInfo
231232

232233
tz = ZoneInfo("Europe/London")
233-
now = datetime.now(tz)
234-
expiry = now + timedelta(hours=1)
235-
result = format_mute_expiry(expiry)
234+
# Pin "now" to midday so expiry (+1h) cannot roll into tomorrow.
235+
# Using the real clock made this flaky in the last hour before midnight.
236+
fixed_now = datetime(2026, 6, 2, 12, 0, tzinfo=tz)
237+
with patch("src.utils.formatting.datetime") as mock_dt:
238+
mock_dt.now.return_value = fixed_now
239+
expiry = fixed_now + timedelta(hours=1)
240+
result = format_mute_expiry(expiry)
236241
assert result.startswith("until ")
237242
assert "tomorrow" not in result
238243

0 commit comments

Comments
 (0)