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
|
e.slug AS entity_slug
|
||||||
FROM check_defs cd
|
FROM check_defs cd
|
||||||
JOIN entities e ON e.id = cd.entity_id
|
JOIN entities e ON e.id = cd.entity_id
|
||||||
|
LEFT JOIN entities tgt ON tgt.id = cd.target_id
|
||||||
WHERE cd.enabled = true
|
WHERE cd.enabled = true
|
||||||
|
AND (tgt.id IS NULL OR tgt.state NOT IN ('deprecated', 'destroyed'))
|
||||||
AND (cd.last_run_at IS NULL
|
AND (cd.last_run_at IS NULL
|
||||||
OR cd.last_run_at <= now() - make_interval(secs => cd.interval_s));
|
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
|
e.slug AS entity_slug
|
||||||
FROM check_defs cd
|
FROM check_defs cd
|
||||||
JOIN entities e ON e.id = cd.entity_id
|
JOIN entities e ON e.id = cd.entity_id
|
||||||
|
LEFT JOIN entities tgt ON tgt.id = cd.target_id
|
||||||
WHERE cd.enabled = true
|
WHERE cd.enabled = true
|
||||||
|
AND (tgt.id IS NULL OR tgt.state NOT IN ('deprecated', 'destroyed'))
|
||||||
AND (cd.last_run_at IS NULL
|
AND (cd.last_run_at IS NULL
|
||||||
OR cd.last_run_at <= now() - make_interval(secs => cd.interval_s))
|
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:
|
case !mon.Declared:
|
||||||
undeclared++
|
undeclared++
|
||||||
case mon.None():
|
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:
|
case e.hasCheck:
|
||||||
if resolveCoverageSignal(ctx, pool, e.id) {
|
if resolveCoverageSignal(ctx, pool, e.id) {
|
||||||
resolved++
|
resolved++
|
||||||
|
|||||||
Reference in New Issue
Block a user