Monitor Apache Airflow DAGs: on_success_callback and on_failure_callback with LastPing
Pass on_success_callback and on_failure_callback
to the DAG() constructor. The success callback GETs the
LastPing URL when all tasks complete; the failure callback POSTs the
task-instance context to /fail. Absence detection handles
what callbacks can't: a scheduler outage that never triggers the DAG at
all. Free, no monitor cap.
The snippets
Create a monitor in
the console, set the
schedule to match your DAG schedule plus a grace window
long enough to cover retries, then copy the ping URL.
DAG-level callbacks (recommended)
One monitor per DAG. The success callback fires when all tasks complete successfully; the failure callback fires when any task exhausts its retries:
Task-level callbacks for granular monitoring
Attach callbacks directly to a task operator for per-task monitoring. Useful when one critical task in a large DAG should have its own monitor:
Using Airflow Variables to store the ping URL
Store the ping URL in an Airflow Variable so it survives DAG code
changes and is visible in the Airflow UI. Use
Variable.get at module level (cached) or inside the
callback (re-fetched each time):
Grace window and retry alignment
Set the LastPing grace window to at least
expected_run_duration + (retries × retry_delay) so
intermediate retries don't open a spurious incident. Only the
final failure (when retries are exhausted) should fire
/fail. See also the
Celery monitoring guide for
task-queue patterns, the
Python guide for script-level
monitoring, and the LastPing MCP server for
AI-agent provisioning.
What this catches
The callbacks report what they can; the silence reports the rest.
- A task failure after retries exhausted —
on_failure_callbackfires and POSTs the task-instance summary to/fail, opening an incident immediately. - DAG success —
on_success_callbackfires and GETs the success ping, resetting the absence timer. - The scheduler itself is down — no DAG run is triggered, no callback fires; the missing ping opens an incident after the grace window.
- A hung task — Airflow's own execution_timeout kills the task, triggering the failure callback, which POSTs to
/fail. - Recovery — the next successful DAG run fires the success callback, closing the incident automatically.
Questions people ask
Front-loaded answers — the most important fact first.
-
Does on_failure_callback fire on each retry or only on final failure?
on_failure_callbackfires on each failed attempt by default. To fire only on final failure, checkcontext['task_instance'].try_number > context['task'].retriesinside the callback before posting to/fail. -
What if the Airflow scheduler is down?
A down scheduler never triggers DAG runs. No callback fires, no ping is sent. Absence-detection monitoring catches this: the missing ping after the grace window opens an incident — no callback code required.
-
Should I use DAG-level or task-level callbacks?
DAG-level is simpler: one monitor per pipeline. Task-level gives per-task visibility but requires more monitors to manage. Start with DAG-level and add task-level monitors only for tasks with their own SLAs.
-
Is this free?
Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See how it compares to Healthchecks.io and Cronitor.
A scheduler outage fires no callback. Absence detection does.
Two callback functions now beat a quiet ETL gap later. First alert wired up in about a minute — and LastPing monitors itself the same way.