A service level agreement (SLA) for data is a promise about freshness: "yesterday's sales are in the mart by 06:00 UTC". Airflow 2 129 's task SLAs checked the time only after a task finished, so a hung run never alerted; Airflow 3.0 removed them, and Airflow 3.1 added Deadline Alerts (still marked experimental in 3.3.2). A deadline is computed when a run starts, from a reference (DAGRUN_QUEUED_AT, DAGRUN_LOGICAL_DATE, FIXED_DATETIME or AVERAGE_RUNTIME) plus an interval; the scheduler checks stored deadlines on every loop and queues the callback as soon as one passes, whether or not the run has finished:
deadline=DeadlineAlert( # Airflow 3.1+: replaces task SLAs
reference=DeadlineReference.DAGRUN_QUEUED_AT,
interval=timedelta(minutes=2),
callback=AsyncCallback(SlackWebhookNotifier, kwargs={
"slack_webhook_conn_id": "booknest_alerts",
"text": "Deadline missed: {{ dag_run.dag_id }} {{ dag_run.dag_run_id }} "
"({{ dag_run.state }}) was due by {{ deadline.deadline_time }}"}),
),An AsyncCallback runs in the triggerer, a SyncCallback on an executor. The callback's template context is small: a dag_run dictionary in the REST API's shape (so dag_run_id, not run_id, which rendered as an empty string on the first try) and deadline. A third run with --conf '{"delay": 150}' held finance_extract for 150 seconds (the alerts are in Slack and PagerDuty Alerts). The 28 June run, done in 10 seconds, raised none, but the failed 29 June run raised one two minutes after it was queued: expect two alerts per failure.