feat(hermes): alert on cron job health - #4304
Conversation
The scheduler records last_status / last_error / last_delivery_error / next_run_at per job, and nothing read it, so a cron stayed dark 40h. A script on the hermes PVC pushes that state to VictoriaMetrics; these are the rules over it. Every expr is wrapped in last_over_time(...[30m]) because the series are pushed, not scraped, and VM's 5m staleness makes a bare selector empty between pushes. Verified live: bare selector returns 0 series, wrapped returns 14.
|
Warning Review limit reached
Next review available in: 40 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Comment |
@@ (root level) @@
# monitoring.coreos.com/v1/PrometheusRule/ai/hermes-rules
! + one document added:
+ apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+ name: hermes-rules
+ namespace: ai
+ labels:
+ kustomize.toolkit.fluxcd.io/name: hermes
+ kustomize.toolkit.fluxcd.io/namespace: ai
+ spec:
+ groups:
+ - name: hermes.rules
+ rules:
+ - alert: HermesCronJobFailed
+ annotations:
+ summary: "Hermes cron {{ $labels.name }} last run failed — it will keep failing on schedule until the cause is fixed"
+ expr: "last_over_time(hermes_cron_last_status_ok[30m]) == 0"
+ for: 15m
+ labels:
+ severity: warning
+ - alert: HermesCronDeliveryFailed
+ annotations:
+ summary: "Hermes cron {{ $labels.name }} ran but could not deliver its output — the result is lost, not late"
+ expr: "last_over_time(hermes_cron_delivery_failed[30m]) == 1"
+ for: 15m
+ labels:
+ severity: warning
+ - alert: HermesCronOverdue
+ annotations:
+ summary: "Hermes cron {{ $labels.name }} is {{ $value | humanizeDuration }} past its scheduled run — the scheduler is not firing it"
+ expr: "last_over_time(hermes_cron_overdue_seconds[30m]) > 3600"
+ for: 15m
+ labels:
+ severity: warning
+ - alert: HermesCronExporterStale
+ annotations:
+ summary: "Hermes cron health metrics are {{ $value | humanizeDuration }} stale — cron alerting is blind, check the hermes pod"
+ expr: "time() - last_over_time(hermes_cron_export_timestamp[2h]) > 1800"
+ for: 5m
+ labels:
+ severity: warning
+ - alert: HermesCronExporterAbsent
+ annotations:
+ summary: "No Hermes cron health metrics at all — the exporter never ran or was removed"
+ expr: absent(last_over_time(hermes_cron_export_timestamp[2h]))
+ labels:
+ severity: warning
|
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| JavaScript | Aug 2, 2026 3:02p.m. | Review ↗ | |
| Shell | Aug 2, 2026 3:02p.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
AI Automated ReviewAnalysis engine: qwen-3.6-fast@http://litellm.ai.svc.cluster.local/v1 (openai) Recommendation: Approve This PR adds well-documented PrometheusRule alerts for the Hermes cron job health exporter. The implementation follows repository conventions for naming, structure, and PromQL patterns used elsewhere in the cluster. Change-by-Change Findings
Standards Compliance
Must-Check Items
Unknowns or Needs VerificationNone. The change is self-contained and relies on an existing exporter ( |
The scheduler already records
last_status,last_error,last_delivery_errorandnext_run_atper job incron/jobs.json. Nothing read it, which is how a cron stayed dark for 40h. A script on the hermes PVC pushes that state to VictoriaMetrics every 10m; these are the rules over it.Five alerts
HermesCronJobFailed,HermesCronDeliveryFailed(delivery is a separate failure from execution — the job can succeed and the post still vanish),HermesCronOverdue,HermesCronExporterStale,HermesCronExporterAbsent.The
last_over_timewrapper is load-bearingThe series are pushed, not scraped, and VM's 5m staleness makes a bare instant selector empty between pushes. Verified live:
Without it
absent()flaps and the failure rules go blind half the time.HermesCronExporterAbsentdeliberately has nofor:—absent()over a 2h window cannot flap, and any delay reopens a gap whereStalehas resolved butAbsenthas not yet fired, reporting "recovered" mid-outage.Validation
kustomize build,kubectl apply --dry-run=server, and every expression run against live VictoriaMetrics.On merge
Fires immediately for jobs currently at
last_status_ok == 0. That is the rule working, not a regression.