Change interval
This commit is contained in:
@@ -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)]
|
||||
Reference in New Issue
Block a user