Airflow backfill и catchup на собеседовании Data Engineer

Готовься к собесу аналитика как в Duolingo
10 минут в день — SQL, Python, A/B, метрики. 1700+ вопросов в Telegram
Открыть Карьерник в Telegram

Карьерник — Duolingo для аналитиков: 10 минут в день тренируй SQL, Python, A/B, статистику, метрики и ещё 3 темы собеса. 1500+ вопросов в Telegram-боте. Бесплатно.

Зачем спрашивают на собесе DE

Backfill — стандартная операция при изменении логики или восстановлении после сбоя. На собесе DE: «как backfill за неделю», «что такое catchup», «depends_on_past». Senior — нюансы intervals.

Catchup

Когда DAG активирован после start_date — Airflow создаёт DAG runs за все пропущенные интервалы.

@dag(
    start_date=datetime(2026, 1, 1),
    schedule="@daily",
    catchup=True   # default
)

Если активирован 2026-05-01 → создаст 121 DAG runs (за каждый день).

Catchup = False. Только run с текущей даты.

catchup=False

Часто полезно — не хочешь, чтобы DAG исторически отрабатывал при первом запуске.

Backfill вручную

CLI:

airflow dags backfill -s 2026-04-01 -e 2026-04-30 my_dag

Запустит DAG runs за каждый день апреля.

Опции:

  • --reset-dagruns — сбросить existing runs.
  • --rerun-failed-tasks — только failed.
  • --ignore-dependencies — пропустить upstream checks.

depends_on_past

Параметр task. Если True → task ждёт, чтобы тот же task в предыдущем run завершился успешно.

my_task = PythonOperator(
    task_id='aggregate',
    python_callable=...,
    depends_on_past=True
)

Когда нужно:

  • Stateful pipeline (например, накопительные счётчики).
  • Tasks, которые не идемпотентны параллельно.

Минус. Один failed run останавливает всю backfill цепь.

wait_for_downstream — ждать, пока ВСЕ downstream предыдущего run завершатся.

Готовься к собесу аналитика как в Duolingo
10 минут в день — SQL, Python, A/B, метрики. 1700+ вопросов в Telegram
Открыть Карьерник в Telegram

Идемпотентность

Backfill подразумевает: повторный запуск того же DAG run не сломает данные.

Bad: INSERT новых строк → backfill дублирует.

Good:

  • DELETE / TRUNCATE партицию + INSERT.
  • MERGE / UPSERT.
  • INSERT OVERWRITE PARTITION.

Партиция = data_interval_start (день, час).

def aggregate(**context):
    ds = context["data_interval_start"].strftime("%Y-%m-%d")
    cur.execute(f"DELETE FROM agg WHERE date = '{ds}'")
    cur.execute(f"INSERT INTO agg ... WHERE date = '{ds}'")

data_interval_start / end

Airflow 2.2+ — переименовано из execution_date.

  • data_interval_start. Начало данных, которые task должен обработать.
  • data_interval_end. Конец интервала.
  • logical_date. Старый execution_date, для совместимости.

Для daily DAG, run от 2026-05-07 00:00:

  • data_interval_start = 2026-05-07 00:00
  • data_interval_end = 2026-05-08 00:00
  • runs реально в начале 2026-05-08 00:00

То есть DAG обрабатывает «прошедший» интервал.

Частые ошибки

Catchup=True для DAG с большим start_date. Создаёт сотни runs одновременно — ненужная нагрузка. catchup=False для новых DAGs.

Не идемпотентный INSERT. Backfill портит данные.

Игнорировать depends_on_past. Если pipeline stateful — без него backfill пропускает зависимости.

Backfill всего DAG при изменении одной task. Запускай только нужную task через --task-regex.

Полагаться на execution_date для данных. Используй data_interval_start / end — они однозначнее.

Связанные темы

FAQ

Что такое max_active_runs?

Лимит одновременных DAG runs. По умолчанию 16. Backfill big — упирается, серилизуется.

Можно backfill в production без downtime?

Да, если идемпотентно. Иначе блокировка / overwrite — нужен maintenance window.

Это официальная информация?

Нет. Статья основана на документации Airflow 2.7+.


Тренируйте Data Engineering — откройте тренажёр с 1500+ вопросами для собесов.