Change interval

This commit is contained in:
Paul Moeller-Friedrich
2026-08-20 09:24:02 +02:00
parent 200186e561
commit 553c035a20
5 changed files with 129 additions and 47 deletions
+67
View File
@@ -0,0 +1,67 @@
"""Rolling scheduler: spreads endpoint checks evenly across the interval.
With N endpoints and `interval_seconds` = T, each endpoint gets its own
slot, T/N seconds apart, and is checked once every T seconds — e.g. 6
endpoints with interval_seconds: 3600 means one endpoint is checked every
10 minutes, rotating through all six over the course of an hour. This is
NOT "check everything, then sleep T seconds": individual endpoint checks
are spread out, not bunched together.
If any single check fails, ALL endpoints are checked once immediately
(out of band) as an extra confirmation pass, and the rotation is then
re-staggered from that point so it stays evenly spread afterward.
"""
from __future__ import annotations
import logging
import time
from typing import List
from .checker import check_all, check_endpoint, log_result
from .influx_writer import write_results
logger = logging.getLogger("uptime_monitor.scheduler")
def run_forever(cfg) -> None:
endpoints = cfg.endpoints
interval = cfg.check.interval_seconds
n = len(endpoints)
stagger = interval / n
now = time.monotonic()
next_at: List[float] = [now + i * stagger for i in range(n)]
logger.info(
"rolling schedule: %d endpoint(s) spread across %ss (~%.1fs apart)",
n, interval, stagger,
)
while True:
idx = min(range(n), key=lambda i: next_at[i])
wait = next_at[idx] - time.monotonic()
if wait > 0:
time.sleep(wait)
ep = endpoints[idx]
result = check_endpoint(ep, cfg.check.timeout_seconds, time.time_ns())
log_result(result)
write_results(cfg.influx, [result])
# schedule this endpoint's next regular slot
next_at[idx] += interval
if not result.success:
logger.warning(
"endpoint=%s failed; re-checking all endpoints immediately in %.0fs",
ep.name, cfg.check.immediate_recheck_delay_seconds,
)
time.sleep(cfg.check.immediate_recheck_delay_seconds)
results = check_all(endpoints, cfg.check.timeout_seconds, time.time_ns())
write_results(cfg.influx, results)
# Re-stagger everyone from now so the rotation stays evenly
# spread out afterward, instead of bunching back up.
now = time.monotonic()
next_at = [now + (i + 1) * stagger for i in range(n)]