| name | apache-airflow-dag-orchestration |
| description | Enterprise Apache Airflow 2.x DAG authoring, TaskFlow API, deferrable operators, idempotent execution models, and production workflow orchestration. |
Apache Airflow DAG Orchestration
Comprehensive architectural guide for authoring resilient, idempotent, and scalable data pipelines using Apache Airflow 2.x+ with TaskFlow API, custom operators, and Kubernetes/Celery executors.
1. Core Architecture & Execution Model
1.1 Airflow Components
- Scheduler: Parses DAG files continuously, evaluates scheduling rules, monitors task state, and enqueues commands to the executor.
- Webserver: Flask/React UI displaying DAG topology, execution history, metrics, and manual triggers.
- Worker: Executes actual task instances (in CeleryWorker pods, K8s Pods, or LocalExecutor threads).
- Triggerer: Runs an asynchronous event loop (asyncio) handling Deferrable Operators (Sensors/Async tasks) to save worker slots.
- Metadata Database: PostgreSQL/MySQL database storing DAG definitions, run history, variables, connection strings, and XComs.
┌───────────────────────────────────────────────────────────────┐
│ Airflow Scheduler │
└──────────────────────────────┬────────────────────────────────┘
│ Reads DAGs & Enqueues Tasks
▼
┌───────────────────┐ ┌─────────────┐ ┌────────────────────┐
│ Metadata Database │ │ Triggerer │ │ Executor / Worker │
└───────────────────┘ └─────────────┘ └────────────────────┘
2. Pipeline Idempotency & Backfill Guarantees
2.1 Deterministic Execution Logic
Every DAG run MUST be deterministic for its target logical_date (data_interval_start). Never rely on system time (datetime.now()) inside execution logic.
SQL_IDEMPOTENT_WRITE = """
DELETE FROM analytics.daily_revenue
WHERE metric_date = '{{ ds }}';
INSERT INTO analytics.daily_revenue (metric_date, total_revenue)
SELECT
DATE(transaction_time) AS metric_date,
SUM(amount) AS total_revenue
FROM raw.transactions
WHERE transaction_time >= '{{ data_interval_start }}'
AND transaction_time < '{{ data_interval_end }}'
GROUP BY 1;
"""
3. Production Anti-Patterns
| Anti-Pattern | Operational Failure | Production Standard |
|---|
Heavy data processing in PythonOperator | Worker memory crash (OOM), blocks worker pool | Offload compute to Spark, Databricks, Snowflake, or EKS/ECS |
Top-level DB / API calls in DAG .py files | Scheduler lag; executes query every 30s during parsing | Move all external connection calls inside @task functions |
| Pushing large DataFrames / payloads into XCom | Database bloat, serializing gigabytes in Metadata DB | Store large artifacts in S3/GCS, pass URI via XCom |
| Synchronous Sensors blocking worker slots | Exhaused worker concurrency slots waiting on external API | Use Deferrable Sensors (deferrable=True) handled by Triggerer |
| Hardcoding credentials or static dates in code | Security vulnerability, broken backfills | Use Airflow Connections/Variables and {{ ds }} macros |
4. Production Implementation Blueprint
TaskFlow API DAG with Deferrable Sensor, Retries, and SLA Alerts
from datetime import datetime, timedelta
import logging
from typing import Dict, Any
from airflow.decorators import dag, task
from airflow.providers.amazon.aws.sensors.s3 import S3KeySensor
from airflow.operators.python import get_current_context
logger = logging.getLogger(__name__)
DEFAULT_ARGS = {
"owner": "data-engineering",
"depends_on_past": False,
"email_on_failure": True,
"email": ["data-alerts@enterprise.com"],
"retries": 3,
"retry_delay": timedelta(minutes=5),
"retry_exponential_backoff": True,
"max_retry_delay": timedelta(minutes=30),
"execution_timeout": timedelta(hours=2),
}
def on_failure_callback(context: Dict[str, Any]) -> None:
"""Alert handler fired on task failure."""
task_id = context.get("task_instance").task_id
dag_id = context.get("dag").dag_id
execution_date = context.get("execution_date")
error = context.get("exception")
logger.error(f"ALERT: Task '{task_id}' in DAG '{dag_id}' failed on . Error: ")
():
wait_for_raw_data = S3KeySensor(
task_id=,
bucket_key=,
wildcard_match=,
aws_conn_id=,
poke_interval=,
timeout=,
deferrable=,
)
() -> :
context = get_current_context()
logical_date = context[]
manifest_uri =
logger.info()
manifest_uri
() -> [, ]:
logger.info()
{: , : }
() -> :
processed_rows = metrics.get(, )
processed_rows <= :
ValueError()
logger.info()
manifest_path = stage_s3_payload()
spark_job = trigger_spark_analytics(manifest_path)
audit = quality_gate(spark_job)
wait_for_raw_data >> manifest_path >> spark_job >> audit
dag_instance = ecommerce_analytics_dag()