Apache Airflow
A paused DAG or a stopped scheduler produces no failed task, so callbacks and email-on-failure stay quiet.
Airflow tells you when a task fails. The failures that cost you are the ones where no task ran: a DAG someone paused and nobody unpaused, a scheduler that stopped or was never restarted after a deploy, a DAG file that stopped parsing so the DAG quietly vanished from the list, or catchup=False on a DAG that was down through its window. on_failure_callback, email_on_failure and the SLA machinery all need a task instance to attach to. There isn't one.
A ping helper with no dependencies
Use the standard library rather than a provider package, so the code does not move when you upgrade Airflow or its HTTP provider:
import urllib.request
PING = "https://vivere.dev/p/<monitor-id>"
def ping(suffix="", body=None):
try:
urllib.request.urlopen(PING + suffix, data=body, timeout=10)
except Exception:
pass # monitoring must never fail the DAG
DAG-level callbacks
with DAG(
dag_id="nightly_etl",
schedule="0 2 * * *", # schedule_interval= on Airflow 2.3 and older
catchup=False,
on_success_callback=lambda ctx: ping(),
on_failure_callback=lambda ctx: ping("/fail", b"dag run failed"),
) as dag:
...
These fire once per DAG run rather than once per task, which is what you want: one monitor should stand for one scheduled thing.
Or a final task
from airflow.operators.bash import BashOperator
done = BashOperator(
task_id="ping_vivere",
bash_command='curl -fsS -m 10 --retry 3 -o /dev/null "$VIVERE_PING_URL"',
env={"VIVERE_PING_URL": "https://vivere.dev/p/<monitor-id>"},
)
transform >> load >> done
A final task is visible in the grid view, which people like, but it is skipped when an upstream task fails, so pair it with on_failure_callback if you want the immediate down alert as well.
Monitor settings
Use a cron expression matching the schedule, in the scheduler's timezone. Set it to the wall-clock time the run starts, not the logical date: a DAG on 0 2 * * * runs at 02:00 for the interval that ended then, so the logical date is a day behind the ping. Build the grace from the DAG's worst normal duration plus how late a busy scheduler starts it; the calculator does that arithmetic.
catchup on, a restarted DAG fires a burst of runs and a burst of pings. Nothing breaks: the monitor only cares about the most recent one.