← К портфолио Airflow DAG Platform preview
Ситуация
Ручной отчёт из Postgres в Google Sheets давал задержки, ошибки копирования и полное отсутствие воспроизводимости
Задача
Заменить ручную выгрузку воспроизводимым идемпотентным пайплайном с DQ-валидацией, алертами и метриками запусков
Действия
Платформа на Airflow 3: DAG-шаблон fetch → validate → write → record_metrics и shared-модули config, dq, alerts, metrics, output, windows
Результат
Два DAG-а по общему шаблону, 64 теста без Airflow-сервисов и БД, CI из четырёх гейтов: ruff, format, mypy, pytest
Стек
PythonApache Airflow 3PostgreSQLGoogle Sheets APIpytestuv
Исходники Смотреть на GitHub → Обновлено: Sep 27, 2026
Содержание
  1. Ситуация
  2. Задача
  3. Действия
  4. DAG-и
  5. Переиспользуемые модули
  6. Стек и запуск
  7. Гейты CI
  8. Результат
  9. Ограничения
  10. Документация
  11. Частые вопросы

Airflow DAG Platform

▶ Схема потока данных — самодостаточный HTML, открывается в браузере — без установки и сборки

Ситуация

Ручной отчёт по продажам — SQL-клиент, копирование агрегата в Google Sheets — давал задержки, ошибки копирования и никакой воспроизводимости. Пропущенный или упавший прогон оставался незамеченным, а новый отчёт приходилось собирать заново.

Задача

От меня требовалось заменить ручную выгрузку воспроизводимым и идемпотентным пайплайном: данные доходят до приёмника по расписанию без ручного вмешательства, падения видны сразу, а новый отчёт добавляется по общему шаблону, а не с нуля.

Действия

DAG-и

DAG Расписание Что делает Приёмник
daily_sales_report @daily Агрегат продаж за сутки (sale_date, product_id, revenue, orders) Google Sheets (или CSV-фолбэк)
weekly_sales_summary @weekly Сводка за неделю по category (category, revenue, orders) CSV (Sheets опционально)

Каждый DAG строится по шаблону fetch → validate → write → record_metrics на @task-декораторах Airflow 3 SDK. Окно — полуинтервал [logical_date − N, logical_date); catchup=False, backfill — явной командой.

Переиспользуемые модули

dags/shared/
  config.py    # конфиг из Airflow Variables, без хардкода
  dq.py        # DQ-валидация перед записью
  alerts.py    # формат и callback алертов при падении
  metrics.py   # observability: запись в dag_metrics
  output.py    # CSV-райтер (dev-фолбэк), идемпотентная перезапись
  windows.py   # daily/weekly окна по logical_date

Стек и запуск

uv sync
uv run pytest                                 # тесты без Airflow runtime
uv run python scripts/generate_sales_data.py --days 7 --rows-per-day 10000
export AIRFLOW_HOME=$(pwd) && uv run airflow standalone   # UI :8080, admin/admin
uv run python scripts/metrics_report.py --days 7

Гейты CI

uv run ruff check .          # линт: E,W,F,I,B,C4,UP
uv run ruff format --check .
uv run mypy                  # dags/, scripts/, tests/
uv run pytest                # 64 теста, хуки замоканы

Результат

Платформа доводит два отчёта до приёмника по расписанию, каждый — отдельный версионируемый DAG. Качество держится на четырёх гейтах CI: ruff check, ruff format --check, mypy и pytest проходят на 64 тестах, которым не нужны ни Airflow-сервисы, ни живая БД (хуки замоканы). Конфигурация целиком вынесена в Airflow Variables с префиксом AIRFLOW_CFG_, а dev-режим output="file" работает без внешних API.

Ограничения

Источник данных синтетический (scripts/generate_sales_data.py), поэтому платформа проверена на демо-данных, а не на прод-потоке. Google Sheets как приёмник требует реального сервисного аккаунта; без него остаётся только CSV-фолбэк. Проект портфельный: надёжность поведения Airflow под нагрузкой на больших объёмах не измерялась.

Документация

Частые вопросы

Почему отчёт — это DAG, а не скрипт?

DAG даёт версионирование, расписание, ретраи и метрики запусков из коробки; ручная выгрузка SQL-клиентом → копирование в Sheets не оставляет ни одного из этих следов.

Что проверяет DQ-валидация?

Заголовок результата, неотрицательные revenue и orders и пустой набор как отдельный NoDataError — до того, как данные уйдут в приёмник.

Как устроена observability?

Каждый успешный запуск пишет строку в dag_metrics (status, duration_s, rows_written, logical_date); провал фиксируется в on_failure_callback. scripts/metrics_report.py агрегирует success rate и p95.

Работает ли проект без внешних API?

Да: в dev-режиме AIRFLOW_CFG_sales_report_output=file пишет CSV в data/out/, а Google Sheets нужен реальный сервисный аккаунт.

Как добавить новый отчёт?

По общему шаблону переиспользования shared-модулей: новый DAG собирается из тех же config, dq, alerts, metrics и windows, без копирования логики.