Lesson 16 · Pipeline patterns & best practices
Reliability & testing DAGs
The practices that make a pipeline one you can trust overnight.
Your win: name the reliability practices — retries, alerting, timeouts/SLAs, data validation — and how DAGs get tested, especially the repo's way.
Surviving failure
- Retries —
retries+retry_delay(Lesson 8) absorb transient failures automatically. - Alerting —
on_failure_callbackfires when a task fails (ourslack_alert(failed_mentions)). - Timeouts / SLAs —
dagrun_timeoutbounds a run's duration (ours = 90 min); SLA / deadline-miss callbacks warn when a task runs long.
Trusting the output — data validation
*-validation Spark tasks and
Great Expectations checks run as steps after the transform, so bad data stops the run and
alerts.
Testing DAGs
At minimum, a DAG parse / import test catches syntax errors, cycles, and bad imports before deploy. Beyond that, unit-test the task logic (the Python/PySpark functions) separately from Airflow.1
rules.yaml + templates and fails if the committed DAGs
differ — so what's deployed always matches the config, and a template mistake is
caught in review. Data correctness is enforced by the in-pipeline *-validation
tasks + Great Expectations rather than a PySpark pytest suite. And the generator itself
validates (failed_mentions required, SparkApp name length).
start_date like now(),
heavy top-level code (parsed every ~30s), and catchup=True with an old
start_date. Getting these wrong is how "the DAG looked fine" becomes a 2am
page.
Airflow Best Practices (testing) + Astronomer's testing guide
DAG-parse tests, unit-testing task logic, and the reliability checklist.
→ airflow.apache.org — Testing a DAG
→ astronomer.io/docs/learn — Testing Airflow
Check yourself (from memory)
Q1. on_failure_callback is used to…
slack_alert(failed_mentions).
Q2. In this repo, DAG correctness is validated mainly by…
*-validation tasks + Great Expectations.
Q3. A good pipeline bounds a run's duration with…
dagrun_timeout (ours = 90 min) fails a run
that overruns, so a stuck job doesn't hang forever.
retry_delay for transient failures (L8),
with alerting via on_failure_callback (our slack_alert(failed_mentions)).
(2) BOUND runs with dagrun_timeout (our 90m) + SLA/miss callbacks. (3) DATA
QUALITY: validate outputs as tasks (our *-validation Spark jobs + Great
Expectations) so bad data fails the DAG. (4) TEST DAGs: at minimum a parse/import test
(no syntax errors, no cycles) + unit-test task logic; this repo's approach is the
generation DRIFT CHECK plus in-pipeline validation. (5) Design well: IDEMPOTENT tasks,
catchup=False, no heavy top-level code, no dynamic start_date.