154 lines
37 KiB
Markdown
154 lines
37 KiB
Markdown
# План обновления практики по Airflow
|
||
|
||
Дата: 2026-09-28. Подход согласован с автором курса. Реализация завершена. Результаты и границы проверки сохранены в [протоколе](../validation/2026-09-28-practice.md).
|
||
|
||
Этот документ сохраняет решения, порядок доработки и результаты проверки. Текущие задания находятся в [educational-tasks.md](../../educational-tasks.md), запуск стенда описан в [README](../../airflow-docker/README.md).
|
||
|
||
## Цель и границы
|
||
|
||
Стенд знакомит студентов с Apache Airflow и входит в [программу Data Engineering](https://de.dementev.space/). Перед ним студенты проходят Python, pandas, SQL и Docker. Самостоятельное построение цельных процессов обработки данных относится к последующим курсовым работам.
|
||
|
||
Результат этого блока: студент умеет запустить готовый DAG, найти его граф и логи, внести небольшое изменение по образцу и объяснить наблюдаемое поведение. Практика остается набором небольших экспериментов с инструментом.
|
||
|
||
Обновление сохраняет ознакомительный формат и версию Airflow 2.9.x. Основной маршрут выполняется на существующем стенде; внешние интеграции относятся к заданиям по желанию. Учебная имитация отдельных операций допустима, если описание и логи честно называют ее имитацией.
|
||
|
||
## Порядок работы
|
||
|
||
Перед продолжением сверить чек-лист с текущими файлами и историей Git. Прочитать согласованные решения ниже, затем выполнить первый незавершенный этап. Локальные решения в этих границах принимать и записывать в рабочей таблице; противоречия с согласованной целью выносить на обсуждение.
|
||
|
||
- [x] Зафиксировать подход и находки в этом документе; добавить ссылки из README стенда и AGENTS.md.
|
||
- [x] **1. Разобрать все исходные задания.** Создать здесь рабочую таблицу с колонками: исходное задание (DAG/раздел и номер), изучаемая возможность, исходное состояние и зависимости, решение с обоснованием, место в будущем маршруте, наблюдаемый результат. Решения: оставить основным, разделить, перенести в дополнительные или переформулировать. Исходный набор - 25 заданий в `educational-tasks.md` на коммите `13e3102`; после переработки число упражнений может измениться. **Готово:** учтены 25 из 25 исходных заданий, у каждой части разделенного задания определена обязательность, а все зависимости основного маршрута обеспечены без выполнения дополнительных упражнений. Сопоставление с главами учебника объясняет выбор тем; новые темы добавляются только при выявленной необходимости для цели блока.
|
||
- [x] **2. Проверить и исправить несогласованности.** Сверить каждую строку раздела "Найденные несогласованности и препятствия" с актуальным кодом. Для каждой записать итог: исправлено, не подтвердилось с объяснением или оставлено как явно описанный учебный сценарий. **Готово:** все находки разобраны; подтвержденные ошибки устранены, измененное поведение проверено на версии стенда. Невыполненная проверка остается открытой.
|
||
- [x] **3. Переработать показательный блок обработки ошибок.** Подготовить основной управляемый эксперимент с повтором, наблюдаемые результаты и отдельное усложнение по желанию. **Готово:** исходное состояние и возврат к нему описаны; воспроизведены успех после повтора и окончательная ошибка; логи, состояния задач и итог DAG Run совпадают с описанием. Этот блок служит образцом объема и оформления остальных упражнений.
|
||
- [x] **4. Переработать остальные блоки.** Применить выбранное распределение и образец к остальным заданиям. **Готово:** каждая строка рабочей таблицы ссылается на итоговое упражнение или содержит причину объединения; у каждого упражнения есть обязательность и проверяемый результат; подготовка и восстановление общих данных описаны там, где нужны.
|
||
- [x] **5. Согласовать навигацию.** Обновить маршрут и оценку прогресса в `educational-tasks.md`, корневом README и README стенда. Сверить `dag-specifications.md` с итоговым содержанием. **Готово:** ссылки ведут к актуальным упражнениям; документы согласованно описывают порядок и условия завершения; устаревшие прототипы и необоснованные оценки времени удалены или исправлены.
|
||
- [x] **6. Пройти маршрут двумя способами.** Выполнить только основную практику, затем дополнительные упражнения с переходами обратно к основной. **Готово:** обе последовательности пройдены в изолированном окружении; указанные результаты подтверждены в данных и UI; сохранены условия запусков, результаты и ограничения по правилам раздела "Как проверять результат доработки".
|
||
|
||
По мере выполнения обновлять рабочую таблицу и чек-лист. У закрытого этапа указывать ссылку на коммит или запись о проверке. Если часть проверок недоступна, записать причину и продолжать независимую работу; соответствующий этап остается незавершенным.
|
||
|
||
## Текущее состояние реализации
|
||
|
||
Исправления DAG сохранены в `cf1b770`, задания и навигация в `d8dfe83`, уточнения после прохождения в `1277bff`. В `f6b450c` задания перенесены в корень репозитория.
|
||
|
||
Все 25 исходных заданий сопоставлены с 34 упражнениями: 16 основных и 18 по желанию. Основной маршрут пройден без дополнительных упражнений. Затем проверены дополнительные расширения и возвраты к базовой схеме, режимам и настройкам. Сохранены [условия и результаты проверки](../validation/2026-09-28-practice.md), [состояния 70 контрольных и диагностических запусков](../validation/2026-09-28-practice-runs.jsonl) и снимки UI.
|
||
|
||
Открытых этапов реализации нет. При следующей правке сверять затронутые задания с кодом и протоколом. Проверка не измеряет трудность на студентах; SMTP проверен локальным приемником, без внешнего почтового провайдера.
|
||
|
||
После независимого педагогического ревью исправлены примеры в главах 2, 7 и 9 и уточнены ссылки на теорию перед практикой. Значимость находок, принятые решения и исполнение примеров записаны в [перепроверке ревью](../validation/2026-09-28-theory-review.md). Предложение расширить основную практику опытом с Clear оставлено до проверки на студентах; состав упражнений сохранен.
|
||
|
||
## Согласованные решения
|
||
|
||
1. **Последовательность внутри блока.** Студент запускает исходный пример, меняет одну существенную настройку или часть графа и наблюдает результат. Изменения основных заданий внутри блока сохраняются.
|
||
2. **Ясное начало каждого блока.** Указаны исходный DAG, необходимые файлы, таблицы и настройки, а также изменения, которые остаются от предыдущей работы. Блок определяется учебным смыслом: загрузка CSV и последующая DQ-проверка могут объединять два DAG.
|
||
3. **Основная практика и задания по желанию.** Обязательность отделена от сложности. Дополнительные задания расположены в конце своего блока; их результаты не нужны для продолжения основной практики. Пропуск дополнительного задания не препятствует завершению блока.
|
||
4. **Разделение смешанных заданий.** Если одно упражнение объединяет знакомство с возможностью Airflow и значительное усложнение, оно разделяется. Например, TaskGroup и настройка настоящей отправки писем не должны быть одним обязательным заданием.
|
||
5. **Наблюдаемый результат.** У каждого задания есть раздел "Что должно получиться": конкретное поведение в UI, сообщение в логах или результат в файле/таблице. Преднамеренная ошибка может быть правильным результатом упражнения.
|
||
6. **Управляемые учебные сценарии.** Основные примеры ветвления и повторных попыток позволяют гарантированно увидеть нужный случай. Случайность допустима в данных, если она не мешает наблюдать изучаемое поведение и проверять результат.
|
||
7. **Понятное завершение.** Основная практика дает достаточное знакомство для перехода дальше по программе. Выполнение всех дополнительных упражнений не является скрытым условием прохождения курса.
|
||
|
||
Дополнительное задание, меняющее общую таблицу или настройку, должно описывать возврат к состоянию, необходимому следующему блоку. Перенос задания в конец раздела сам по себе эту проблему не решает. Восстановление касается только объектов упражнения, без общего сброса стенда или чужих изменений.
|
||
|
||
## Как оформлять задания
|
||
|
||
Задания находятся в корне репозитория рядом с главами учебника: `educational-tasks.md`. В `airflow-docker/` остаются инструкция запуска, стенд и примеры DAG. Основные и дополнительные упражнения сохраняются в одном документе.
|
||
|
||
В начале блока: связь с главами учебника, необходимые исходные условия и короткий запуск готового примера. У задания:
|
||
|
||
- пометка "Основная практика" или "По желанию"; сложность указывается отдельно;
|
||
- конкретное изменение, позволяющее познакомиться с одной возможностью Airflow;
|
||
- подсказка по необходимости;
|
||
- "Что должно получиться" с указанием места проверки;
|
||
- для экспериментов с ошибками - способ вызвать ошибку и вернуть нормальное поведение;
|
||
- при необходимости один короткий вопрос о причине наблюдаемого результата.
|
||
|
||
Для ветвления и обработки ошибок проверяются статусы отдельных задач и всего DAG Run. Формулировка "всё зеленое" не подходит для сценария с ожидаемыми пропусками или ошибками. Проверка результата не должна требовать ожидания недельного расписания или неограниченного числа случайных запусков.
|
||
|
||
## Распределение содержания
|
||
|
||
Распределение уточнено после разбора 25 исходных заданий. Номера итоговых упражнений указаны в рабочей таблице ниже; правила прохождения находятся в разделе "Согласованные решения".
|
||
|
||
| Блок | Основная практика | Возможное усложнение по желанию |
|
||
|---|---|---|
|
||
| Первый DAG | Запуск, граф, логи, добавление задачи по образцу, зависимости, знакомство с расписанием | Дополнительные эксперименты с ограничениями запусков |
|
||
| SQL и Connections | Выполнение SQL, смена подключения, наблюдение результата и ошибки подключения | Дополнительные отчеты и расширение модели данных |
|
||
| Файлы и преобразования | Проследить путь файла между задачами, изменить простое преобразование или проверку | Новые поля, отчеты, обработка по отделам |
|
||
| CSV → PostgreSQL → DQ | Проследить загрузку, найти путь к файлу в XCom, добавить проверку, увидеть корректные и ошибочные данные | Расширение схемы с согласованным изменением загрузчика и DQ, общая сводка проверок |
|
||
| Пример ETL | Прочитать граф с параллельными задачами, найти промежуточные и итоговые результаты | Новый источник, расширенная аналитика, архивирование |
|
||
| Ветвление и Variables | Управляемо выбрать ветку, увидеть `skipped`, понять слияние веток | Третья ветка и полноценная обработка разных форматов |
|
||
| Ошибки и повторы | Вызвать ошибку, увидеть повтор и успешное завершение, найти причину в логах | Экспоненциальная задержка, разные исключения, эскалация |
|
||
| Пулы, XCom и TaskGroup | Ожидание слотов, новая метрика XCom, группировка существующих задач | XCom в Bash-шаблоне; настоящая отправка писем на примере с ошибками |
|
||
|
||
Чтение и изменение XCom не должно зависеть от выполнения дополнительного задания по резервному копированию. Для знакомства с пулами достаточно готовых задач с наблюдаемой длительностью; написание механизма резервного копирования не является целью такого эксперимента.
|
||
|
||
## Разбор 25 исходных заданий
|
||
|
||
Номера слева относятся к версии `13e3102`, номера справа - к новой редакции `educational-tasks.md`. Состав основной практики покрывает темы глав 4-9; главы 1-3 дают контекст перед запуском. Обработка по интервалам и самостоятельный проект остаются следующей ступенью программы.
|
||
|
||
| Исходное задание | Возможность | Вход и зависимости | Решение и причина | Новое место | Наблюдаемый результат |
|
||
|---|---|---|---|---|---|
|
||
| hello_world / 1 | PythonOperator, зависимости | Исходный DAG | Основное: небольшое изменение графа | [1.1](../../educational-tasks.md#first-dag) | Новая задача и ее сообщение видны в UI |
|
||
| hello_world / 2 | Расписание, ограничения запусков | После 1.1 | Разделить: расписание основное, конкуренция по желанию | [1.3, 1.A](../../educational-tasks.md#first-dag) | Видно расписание; второй запуск ожидает при лимите 1 |
|
||
| hello_world / 3 | BashOperator | После 1.1 | Основное: другой оператор и файл | [1.2](../../educational-tasks.md#first-dag) | Файл содержит ожидаемый текст |
|
||
| sql_basic / 1 | SQL в задаче, схема таблицы | Исходный SQL-DAG и training | Разделить: UPDATE основное, схема по желанию | [2.2, 2.A](../../educational-tasks.md#sql) | Возраст изменен; дополнительная колонка заполнена |
|
||
| sql_basic / 2 | PostgresHook и отчет | После 2.2, таблица с тремя строками | По желанию: дополнительная обработка | [2.B](../../educational-tasks.md#sql) | Файл: 3 студента, средний возраст 23.33 после UPDATE |
|
||
| sql_basic / 3 | Connections и диагностика | Учебная БД, собственный Conn Id | Основное; вместо неопределенного обработчика - найти и исправить ошибку подключения | [2.1](../../educational-tasks.md#sql) | Ошибка видна в логах, после исправления запуск успешен |
|
||
| file_operations / 1 | Генерация, валидация | Исходный файловый DAG | Разделить: простая трансформация основная, новые поля по желанию | [3.1, 3.A](../../educational-tasks.md#files) | 100 обработанных строк; поля и фильтр проверены отдельно |
|
||
| file_operations / 2 | Отчет по отделам | Требует 3.A | По желанию; график исключен, поскольку требует отдельной зависимости и не знакомит с новой возможностью Airflow | [3.B](../../educational-tasks.md#files) | Сумма численности отделов равна числу строк входа |
|
||
| file_operations / 3 | Параллельность, DQ, retries | Требует 3.A | По желанию; параллельность также видна в основном ETL-примере | [3.C](../../educational-tasks.md#files) | Раздельные файлы покрывают все отделы, сборка читает их |
|
||
| csv_to_postgres / 1 | Проведение поля через загрузку | После основной загрузки и DQ | По желанию: согласовать все четыре SQL/CSV-участка и проверку схемы | [4.A](../../educational-tasks.md#load-dq) | status заполнен; DQ проходит; исходная схема восстановлена |
|
||
| csv_to_postgres / 2 | Специализированный оператор | Базовая схема orders | По желанию: сравнение двух реализаций уже знакомого действия | [4.B](../../educational-tasks.md#load-dq) | После замены оператора загрузка и DQ успешны |
|
||
| csv_to_postgres_dq / 1 | Новая проверка, ошибка данных | Основная загрузка orders | Основное: положительный и отрицательный сценарии | [4.2](../../educational-tasks.md#load-dq) | Отрицательная сумма вызывает failed; восстановление возвращает success |
|
||
| csv_to_postgres_dq / 2 | Trigger Rules и итог DAG Run | После 4.2 | По желанию: запуск всех проверок и общая сводка | [4.C](../../educational-tasks.md#load-dq) | Все проверки завершаются, итог сохраняет ошибку |
|
||
| data_processing / 1 | Несколько источников | Исходный ETL, свои CSV | По желанию; основной разбор графа добавлен перед расширениями | [5.1, 5.A](../../educational-tasks.md#etl) | После JOIN остаются 6 заказов и выручка 2105 |
|
||
| data_processing / 2 | Отчет pandas | После основного запуска, products не нужен | По желанию | [5.B](../../educational-tasks.md#etl) | Топ заказов и средние сверяются с шестью исходными строками |
|
||
| data_processing / 3 | Валидация, callback, архив | После 5.1; поля продуктов необязательны | По желанию с конкретной ошибкой и восстановлением | [5.C](../../educational-tasks.md#etl) | При ошибке архив не создается; после исправления совпадает с результатом |
|
||
| branching / 1 | Выбор ветки и слияние | Исходный DAG, Variable branch_format | Разделить: две управляемые ветки основные, третья по желанию | [6.1, 6.A](../../educational-tasks.md#branching) | Выбранная ветка success, другая skipped, слияние success |
|
||
| branching / 2 | Работа выбранной ветки с данными | Два явно заданных входных файла | По желанию; использовать XCom текущего запуска вместо старых файлов другой ветки | [6.B](../../educational-tasks.md#branching) | Оба формата дают одинаковые агрегаты в отдельных запусках |
|
||
| branching / 3 | Variables, неизвестный параметр | После 6.1 | Variable включена в основное; fallback объединен с третьей веткой | [6.1, 6.A](../../educational-tasks.md#branching) | Неизвестное значение дает понятную ошибку либо review-ветку после расширения |
|
||
| error_handling / 1 | Повторы и задержка | Исходный DAG, Variable error_mode | Разделить: один управляемый повтор основной, backoff по желанию | [7.1, 7.2, 7.A](../../educational-tasks.md#errors) | Две попытки; с нулем повторов - failed |
|
||
| error_handling / 2 | Типы ошибок и оповещение | После 7.2 | По желанию; локальный callback без внешней почты | [7.B](../../educational-tasks.md#errors) | После исчерпания повторов есть сообщение с task_id и причиной |
|
||
| error_handling / 3 | logging | После 7.1 | Основное небольшое дополнение вместо механической замены всех print | [7.3](../../educational-tasks.md#errors) | Собственные сообщения видны в логах |
|
||
| Дополнительные / 1 | Пулы и слоты | Готовый resource_management_dag, пул из 2 слотов | Основной короткий эксперимент; резервное копирование заменено имитацией чтения | [8.1](../../educational-tasks.md#resources) | Задачи с весами 2 и 1 выполняются последовательно |
|
||
| Дополнительные / 2 | XCom и Jinja | После 8.1 | Основная метрика; шаблон Bash по желанию | [8.2, 8.A](../../educational-tasks.md#resources) | total_rows = 50, шаблон выводит то же значение |
|
||
| Дополнительные / 3 | TaskGroup и алертинг | После 8.2; для почты нужен SMTP | Разделить: группировка основная, внешняя доставка по желанию | [8.3, 8.B](../../educational-tasks.md#resources) | Группа раскрывается; XCom работает с полными task_id |
|
||
|
||
Основной маршрут сохраняет изменения внутри блоков. Общие данные есть только в паре загрузка/DQ; изменение схемы вынесено после основных опытов, с обратным ALTER и возвратом списков колонок. Задания 3.B и 3.C явно зависят от дополнительного 3.A, но дальнейшая основная практика от этой ветки не зависит. Variables возвращаются к исходным значениям перед переходом дальше.
|
||
|
||
## Найденные несогласованности и препятствия
|
||
|
||
Первичные находки подтвердились при чтении кода и выполнении. Ниже их итоговое состояние; подробные результаты приведены в [протоколе](../validation/2026-09-28-practice.md).
|
||
|
||
| Место | Исходная проблема | Итог |
|
||
|---|---|---|
|
||
| SQL | DROP после вставки не готовил существующую таблицу к новой колонке; результат очищался до проверки. | Исправлено: TRUNCATE перед вставкой, task_id `truncate_table`, три строки остаются в БД. В 2.A ALTER выполняется до запуска. Проверены UPDATE, email и отчет. |
|
||
| Загрузчик CSV | Подсказка про status пропускала INSERT ... SELECT. | Исправлено: перечислены четыре участка загрузчика и порядок полей CSV/COPY. Проверены значения статусов в БД, а не только наличие колонки. |
|
||
| Схема DQ | Дополнительная колонка конфликтовала с ожидаемыми четырьмя. | Исправлено: расширение идет после основного DQ; описаны обновление ожидания и возврат схемы. Оба состояния проверены. |
|
||
| Trigger Rules DQ | После отказа обещан skipped. | Исправлено на upstream_failed; подтверждены отказ проверки суммы и отказ схемы. |
|
||
| Обработчики ошибок | chain связывал списки попарно. | Исправлено: оба обработчика имеют обе рабочие задачи в непосредственных предшественниках. Проверены успех, повтор, отказ первой, второй и обеих задач, общий итог DAG Run. |
|
||
| Сводка DQ и алертинг | Единственная успешная завершающая задача с all_done могла скрыть ошибку; письмо безусловно сообщало об успехе. | Исправлено: сводка сверяет состояния и падает при неуспешной проверке. Уведомления назначены callbacks задачи и DAG. Проверены all_done, письма об отказе/успехе и сохранение результата при ошибке SMTP. |
|
||
| ETL | Transform обходил результаты Extract, имитация называлась загрузкой в БД. | Исправлен путь данных. Имитация сохранена и явно обозначена именем simulate_load и логом. Фильтрация Extract изменила отчет с 6/2105 на 4/2000. |
|
||
| Пулы | Формулировка "не более двух задач" не показывала ограничение по весам. | Добавлен готовый пример: в пуле из двух слотов веса 2+1 выполняются последовательно, 1+1 пересекаются по времени. Проверены оба варианта. |
|
||
| Ветвление, повторы и зависимости | Случайность мешала наблюдать нужный случай; использовались неопределенные входы и результаты старых запусков. | Исправлено: Variables управляют режимами; входы CSV/JSON заданы; слияние читает XCom текущего запуска; зависимости дополнительных упражнений указаны явно. |
|
||
| Логи callbacks | Первоначальная инструкция отправляла все сообщения в docker compose logs scheduler. | Уточнено после выполнения: callback оператора виден в последней попытке задачи, callback DAG в файле scheduler. Оба места проверены. |
|
||
|
||
Технические источники: [chain](https://airflow.apache.org/docs/apache-airflow/2.9.2/_api/airflow/models/baseoperator/index.html#airflow.models.baseoperator.chain), [статусы задач](https://airflow.apache.org/docs/apache-airflow/2.9.2/core-concepts/tasks.html#task-instances), [итог DAG Run](https://airflow.apache.org/docs/apache-airflow/2.9.2/core-concepts/dag-run.html#dag-run-status), [пулы](https://airflow.apache.org/docs/apache-airflow/2.9.2/administration-and-deployment/pools.html), [COPY в PostgreSQL 16](https://www.postgresql.org/docs/16/sql-copy.html). Условия поиска логов уточнены по фактическому стенду 2.9.2.
|
||
|
||
## Как проверять результат доработки
|
||
|
||
Результаты проверок сохранять в этом документе рядом с закрываемым этапом: проверенная версия/коммит, сценарий и исходное состояние, ожидаемый и фактический результат, способ проверки. Для длинных логов или снимков экрана достаточно ссылки на доступный артефакт. Версию Airflow сверять с фактическим окружением, а не только с тегом образа в Dockerfile.
|
||
|
||
Проверки разделяются по уровню доказательств:
|
||
|
||
- **Документы и исходники:** все 25 исходных заданий учтены, ссылки работают, имена файлов/задач/таблиц совпадают, обязательность и зависимости согласованы.
|
||
- **Стенд:** подтверждены версия Airflow и загрузка DAG без ошибок импорта; выполнены затронутые сценарии и проверены файлы/таблицы. Проверка синтаксиса Python не заменяет выполнение задач.
|
||
- **UI:** студент действительно может найти указанные состояния, логи, XCom, граф и настройки; показанные результаты совпадают с текстом.
|
||
- **Прохождение:** отдельно проверены основной маршрут и переходы после дополнительных заданий. Не выполненные проверки так и отмечаются; предполагаемое время не выдается за измеренное на студентах.
|
||
|
||
Эксперименты с изменением данных выполняются в изолированном учебном окружении. Проверка не должна затрагивать другие работающие стенды или несвязанные изменения пользователя.
|
||
|
||
## Почему выбран этот формат
|
||
|
||
Одни метки сложности не разделяют смешанные упражнения и не объясняют условия продолжения. Полностью независимые задания увеличивают повторную подготовку. Отдельный сборник усложнений разрывает связь с исходным примером. Демонстрации без изменения кода дают меньше практики, а самостоятельный большой пайплайн дублирует цель последующих курсовых.
|
||
|
||
Выбранный формат сохраняет практику изменения кода и позволяет переходить к следующему блоку после знакомства с нужными возможностями Airflow.
|