fix(scheduler): stop monitoring deprecated/destroyed targets
ListEnabledCheckDefs now LEFT JOINs the target entity and excludes rows whose target is deprecated or destroyed, so retired things (secrets-issuance, homelab-mcp, the dead secrets ingress route) stop generating permanent false alarms instead of waiting for an operator to disable the check_def by hand. coverageSweep's None() branch previously did nothing, so a type changed from declared monitoring to `monitoring: none` (dns-zone) left its open `unmonitored` signals lingering forever — a None() entity never gains a check, so the hasCheck resolution path never fired. It now resolves those signals.
This commit is contained in:
@@ -63,7 +63,9 @@ SELECT cd.entity_id, cd.target_id, cd.target_type, cd.kind, cd.config,
|
||||
e.slug AS entity_slug
|
||||
FROM check_defs cd
|
||||
JOIN entities e ON e.id = cd.entity_id
|
||||
LEFT JOIN entities tgt ON tgt.id = cd.target_id
|
||||
WHERE cd.enabled = true
|
||||
AND (tgt.id IS NULL OR tgt.state NOT IN ('deprecated', 'destroyed'))
|
||||
AND (cd.last_run_at IS NULL
|
||||
OR cd.last_run_at <= now() - make_interval(secs => cd.interval_s));
|
||||
|
||||
|
||||
@@ -696,7 +696,9 @@ SELECT cd.entity_id, cd.target_id, cd.target_type, cd.kind, cd.config,
|
||||
e.slug AS entity_slug
|
||||
FROM check_defs cd
|
||||
JOIN entities e ON e.id = cd.entity_id
|
||||
LEFT JOIN entities tgt ON tgt.id = cd.target_id
|
||||
WHERE cd.enabled = true
|
||||
AND (tgt.id IS NULL OR tgt.state NOT IN ('deprecated', 'destroyed'))
|
||||
AND (cd.last_run_at IS NULL
|
||||
OR cd.last_run_at <= now() - make_interval(secs => cd.interval_s))
|
||||
`
|
||||
|
||||
@@ -85,7 +85,16 @@ func coverageSweep(ctx context.Context, pool *db.Pool) {
|
||||
case !mon.Declared:
|
||||
undeclared++
|
||||
case mon.None():
|
||||
// Explicitly unmonitorable. Nothing to say.
|
||||
// Explicitly unmonitorable. Nothing to raise — but a type that
|
||||
// USED to declare monitoring (e.g. dns-zone, [dns]→none) may have
|
||||
// open `unmonitored` signals from before the change. They are no
|
||||
// longer a gap, so close them; otherwise they linger forever,
|
||||
// because resolveCoverageSignal only runs from the hasCheck path
|
||||
// and a None() entity never gains a check.
|
||||
if resolveCoverageSignal(ctx, pool, e.id) {
|
||||
resolved++
|
||||
slog.Info("scheduler: type now unmonitorable, resolving stale signal", "entity", e.slug)
|
||||
}
|
||||
case e.hasCheck:
|
||||
if resolveCoverageSignal(ctx, pool, e.id) {
|
||||
resolved++
|
||||
|
||||
Reference in New Issue
Block a user