Express a freshness check as a metric and an alert
The first hands-on of the series: declare a freshness SLA, express staleness as a metric, and write an alert rule — including what happens when no data arrives at all. Ends with the pre-merge check that keeps schedules honest against the SLA they claim.
At a glance
| When | You are adding the first data-quality alert for a table; A schedule change is proposed and someone asks what it does to the SLA |
|---|---|
| Where | Data Observability |
| Why | A freshness SLA that lives in a wiki page guards nothing — encode it as a metric and an alert and it defends itself. |
Learning objectives
- Declare a freshness SLA and compute worst-case lag from a schedule
- Express staleness as a metric and write an alerting rule
- Configure no-data handling so silence is an alert, not a pass
What you need
- A table with a declared freshness SLA (in hours)
- A Prometheus + Grafana stack, or any metrics store with alert rules you can edit
Steps
- Declare the contract — a freshness SLA per source, the number the hook can warn against when a change would silently widen it. (from hook-freshness-pre-merge )
- Learn the arithmetic the SLA needs — compare the schedule in the diff with the declared SLA and compute the worst-case lag. (from hook-freshness-pre-merge )
- Run the example — a cron changed from hourly to daily violates a 6h freshness SLA; the check warns with the computed lag. (from hook-freshness-pre-merge )
- Express staleness as a metric — the pull-based metrics model, PromQL, exporters, service discovery and alerting rules are what turn "table age" into a queryable series. (from ref-prometheus-docs )
- Trust the semantics — the metrics model and PromQL semantics pages settle how to express and alert on pipeline metrics. (from ref-prometheus-docs )
- Put the alert somewhere real — dashboards, panel queries and alerting including the unified alerting model, the surface where pipeline freshness dashboards live. (from ref-grafana-docs )
- Handle the silence — alerting semantics (no-data handling, evaluation intervals) are documented precisely; configure them or an absent series passes as health. (from ref-grafana-docs )
Check yourself
- A daily schedule against a 6h SLA fails by construction — worst-case lag is 24h, not 6h.
- An absent series is not a healthy one — no-data handling decides whether silence pages you.
Worked example
Staleness as a metric and an alert rule — from ref-prometheus-docs
# illustrative sketch of the model the docs define —
# exporter exposes last success, PromQL computes staleness,
# an alerting rule compares it to the SLA
pipeline_last_success_timestamp{table="orders"}
staleness_seconds = now - pipeline_last_success_timestamp
alert if staleness_seconds > freshness_sla{table="orders"}
The worst-case lag rule — from hook-freshness-pre-merge
Compare the schedule/cron in the diff with the source's declared
freshness SLA. If the new schedule can produce data older than the
SLA (e.g. daily when the SLA is 6h), warn with the computed
worst-case lag.
The no-data decision — from ref-grafana-docs
Alerting semantics to set on every rule — no-data handling and the
evaluation interval. Decide what an absent series means before the
first silent night, not after it.
Sourced from
Security scan
Last sweep 2026-10-24: 0 finding(s), 0 marked as examples.
Common gotchas
- No-data is not healthy — an absent series under default handling never fires the alert.
- The evaluation interval adds detection lag — a 6h SLA checked hourly can page an hour late.
- Design for worst-case lag, not average — a schedule that can emit 24h-old data eventually will.
Production considerations
- Store the SLA next to the dataset definition so the metric, the alert and the docs share one number.
- Route data-signal alerts to the table owner from the catalog, not to a shared channel.
Diagram
freshness SLA ──▶ staleness metric ──▶ alert rule
|
|- cron × interval ─▶ worst-case lag ─▶ compare to SLA
|
|- no-data? ─▶ decide: fire (default) or pass (rare)
|
|- pre-merge: cron in diff vs SLA ─▶ warn before it pages anyone
Registry stats
| Verification | community · Oct 24, 2026 |
|---|---|
| Completeness | 81 |
| Trust multiplier | ×1.25 |
| Composite | 34.15 · adequate |
| Freshness | 0 days since last source check |
| Difficulty | beginner |
| Version | 0.1.0 |
| License | CC-BY-4.0 |
| Security flags | none |
Did this solve your problem?
Express a freshness check as a metric and an alert