Skill 寫法圖鑑

airflow-dag-patterns

wshobson | 資料與分析 | 原文 | MIT

用 operator、sensor、測試和部署的最佳實務,建構可上線的 Airflow DAG

中文翻譯

---
name: airflow-dag-patterns
description: 用 operator、sensor、測試和部署的最佳實務,建構可上線的 Apache Airflow DAG。在建立資料 pipeline、編排工作流程或排程批次作業時使用。
---

# Apache Airflow DAG 模式

可上線的 Apache Airflow 模式,涵蓋 DAG 設計、operator、sensor、測試和部署策略。

## 何時使用這個 Skill

- 用 Airflow 建立資料 pipeline 編排
- 設計 DAG 結構和相依關係
- 實作自訂的 operator 和 sensor
- 在本機測試 Airflow DAG
- 在正式環境架設 Airflow
- 除錯失敗的 DAG 執行

## 核心概念

### 1. DAG 設計原則

| 原則       | 說明                         |
| --------------- | ----------------------------------- |
| **Idempotent**  | 跑兩次得到相同結果  |
| **Atomic**      | task 要嘛完全成功,要嘛完全失敗    |
| **Incremental** | 只處理新增或有變動的資料       |
| **Observable**  | 每一步都有 log、metric、警報 |

### 2. Task 相依關係

```python
# Linear
task1 >> task2 >> task3

# Fan-out
task1 >> [task2, task3, task4]

# Fan-in
[task1, task2, task3] >> task4

# Complex
task1 >> task2 >> task4
task1 >> task3 >> task4
```

## 快速開始

```python
# dags/example_dag.py
from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.operators.empty import EmptyOperator

default_args = {
    'owner': 'data-team',
    'depends_on_past': False,
    'email_on_failure': True,
    'email_on_retry': False,
    'retries': 3,
    'retry_delay': timedelta(minutes=5),
    'retry_exponential_backoff': True,
    'max_retry_delay': timedelta(hours=1),
}

with DAG(
    dag_id='example_etl',
    default_args=default_args,
    description='Example ETL pipeline',
    schedule='0 6 * * *',  # 每天早上 6 點
    start_date=datetime(2024, 1, 1),
    catchup=False,
    tags=['etl', 'example'],
    max_active_runs=1,
) as dag:

    start = EmptyOperator(task_id='start')

    def extract_data(**context):
        execution_date = context['ds']
        # 在這裡寫 extract 邏輯
        return {'records': 1000}

    extract = PythonOperator(
        task_id='extract',
        python_callable=extract_data,
    )

    end = EmptyOperator(task_id='end')

    start >> extract >> end
```

## 詳細模式與實作範例

詳細的模式文件放在 `references/details.md`。上面的導覽層不夠用時,再讀那個檔案。

## 最佳實務

### 該做的

- **用 TaskFlow API** - 程式碼更乾淨,XCom 自動處理
- **設定 timeout** - 避免殭屍 task
- **用 `mode='reschedule'`** - 給 sensor 用,釋放 worker
- **測試 DAG** - 單元測試和整合測試
- **Idempotent 的 task** - 重試起來很安全

### 不該做的

- **不要用 `depends_on_past=True`** - 會造成瓶頸
- **不要寫死日期** - 用 `{{ ds }}` macro
- **不要用全域 state** - task 應該是無狀態的
- **不要盲目跳過 catchup** - 要先理解影響
- **不要把繁重的邏輯放在 DAG 檔案裡** - 從模組 import

英文原文

---
name: airflow-dag-patterns
description: Build production Apache Airflow DAGs with best practices for operators, sensors, testing, and deployment. Use when creating data pipelines, orchestrating workflows, or scheduling batch jobs.
---

# Apache Airflow DAG Patterns

Production-ready patterns for Apache Airflow including DAG design, operators, sensors, testing, and deployment strategies.

## When to Use This Skill

- Creating data pipeline orchestration with Airflow
- Designing DAG structures and dependencies
- Implementing custom operators and sensors
- Testing Airflow DAGs locally
- Setting up Airflow in production
- Debugging failed DAG runs

## Core Concepts

### 1. DAG Design Principles

| Principle       | Description                         |
| --------------- | ----------------------------------- |
| **Idempotent**  | Running twice produces same result  |
| **Atomic**      | Tasks succeed or fail completely    |
| **Incremental** | Process only new/changed data       |
| **Observable**  | Logs, metrics, alerts at every step |

### 2. Task Dependencies

```python
# Linear
task1 >> task2 >> task3

# Fan-out
task1 >> [task2, task3, task4]

# Fan-in
[task1, task2, task3] >> task4

# Complex
task1 >> task2 >> task4
task1 >> task3 >> task4
```

## Quick Start

```python
# dags/example_dag.py
from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.operators.empty import EmptyOperator

default_args = {
    'owner': 'data-team',
    'depends_on_past': False,
    'email_on_failure': True,
    'email_on_retry': False,
    'retries': 3,
    'retry_delay': timedelta(minutes=5),
    'retry_exponential_backoff': True,
    'max_retry_delay': timedelta(hours=1),
}

with DAG(
    dag_id='example_etl',
    default_args=default_args,
    description='Example ETL pipeline',
    schedule='0 6 * * *',  # Daily at 6 AM
    start_date=datetime(2024, 1, 1),
    catchup=False,
    tags=['etl', 'example'],
    max_active_runs=1,
) as dag:

    start = EmptyOperator(task_id='start')

    def extract_data(**context):
        execution_date = context['ds']
        # Extract logic here
        return {'records': 1000}

    extract = PythonOperator(
        task_id='extract',
        python_callable=extract_data,
    )

    end = EmptyOperator(task_id='end')

    start >> extract >> end
```

## Detailed patterns and worked examples

Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient.

## Best Practices

### Do's

- **Use TaskFlow API** - Cleaner code, automatic XCom
- **Set timeouts** - Prevent zombie tasks
- **Use `mode='reschedule'`** - For sensors, free up workers
- **Test DAGs** - Unit tests and integration tests
- **Idempotent tasks** - Safe to retry

### Don'ts

- **Don't use `depends_on_past=True`** - Creates bottlenecks
- **Don't hardcode dates** - Use `{{ ds }}` macros
- **Don't use global state** - Tasks should be stateless
- **Don't skip catchup blindly** - Understand implications
- **Don't put heavy logic in DAG file** - Import from modules