Data Engineering/Orchestration & Quality

Intermediate7 min read

Orchestrating Pipelines with DAGs

Why pipelines are modeled as directed acyclic graphs, what tools like Airflow and Dagster actually coordinate, and the scheduling concepts that trip up beginners.

A real pipeline is rarely one script — it's a set of tasks with dependencies: extract before transform, transform before load, load before the downstream report refreshes. Orchestration tools exist to schedule, sequence, retry, and monitor exactly this kind of multi-step workflow.

Why a DAG (directed acyclic graph)

Pipelines are modeled as DAGs — directed, because dependencies flow one way (task B waits for task A), and acyclic, because a valid pipeline can never loop back on itself (that would mean a task depends on its own future output). Tools like Apache Airflow, Dagster, and Prefect let you define this graph in code and handle the mechanics of running it: scheduling, parallelizing independent branches, retrying failed tasks, and alerting when something breaks.

# A simplified Airflow-style DAG definition
with DAG("daily_orders", schedule="@daily") as dag:
    extract = PythonOperator(task_id="extract_orders", python_callable=extract_orders)
    transform = PythonOperator(task_id="transform_orders", python_callable=transform_orders)
    load = PythonOperator(task_id="load_orders", python_callable=load_orders)

    extract >> transform >> load  # dependency order

Concepts that trip up beginners

  • Schedule interval vs. execution date: a run 'for' yesterday often actually executes today
  • Idempotency: re-running a task for the same input should produce the same result, not duplicate it
  • Backfilling: running a DAG for past dates it missed or that predate its creation
  • Sensors/triggers: tasks that wait for an external condition (a file landing, an upstream DAG finishing) rather than running on a fixed clock

Tip — Idempotency is the habit that saves you

Design every task so running it twice for the same input is safe — e.g. overwrite a partition rather than append to it. Pipelines fail and get retried constantly; non-idempotent tasks turn a retry into a data quality incident.

Orchestration is ultimately about making failure boring: when (not if) a task fails, the system should retry sensibly, alert the right person, and let you re-run just the affected part of the graph rather than the whole pipeline.