refactor(dags): параллелизован граф DAG bookings_to_gp_stage

- Зачем:
  - линейный граф маскировал реальные зависимости данных; для эталонного
    стенда важно показать менти параллельный граф там, где данные независимы.
- Что:
  - airports и airplanes грузятся параллельно после check_tickets_dq.
  - routes ждёт обоих (DQ проверяет ссылочную целостность на оба справочника).
  - seats зависит только от airplanes и работает параллельно с веткой
    routes → flights → segments → boarding_passes.
  - finish_summary ждёт обе ветки (check_boarding_passes_dq + check_seats_dq).
  - datetime.utcnow() заменён на datetime.now(UTC) в csv_to_greenplum.py.
  - smoke-тесты дополнены проверкой параллельности и второй ветки.
  - документация обновлена с ASCII-схемой нового графа.
- Проверка:
  - make test (11 passed, 4 skipped), make lint — чисто.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 22:12:22 +03:00
co-authored by Claude Opus 4.6
parent 3dcaeb85ce
commit 39ff430ed0
4 changed files with 83 additions and 29 deletions
+21 -7
View File
@@ -87,26 +87,40 @@ make bookings-init
- проверяет количество строк в том же окне инкремента, а также ссылочную целостность и обязательные поля;
- при проблемах делает `RAISE EXCEPTION`, чтобы DAG падал “красным”.
6) Справочники (full load)
6) Справочники (full load, параллельно где возможно)
Каждый справочник загружается “снэпшотом” (все строки) и затем проверяется DQ-скриптом:
Справочники загружаются “снэпшотом” (все строки) и затем проверяются DQ-скриптом.
Порядок определяется зависимостями данных — **airports** и **airplanes** грузятся **параллельно**,
потому что не зависят друг от друга:
```
check_tickets_dq
├─ load_airports → check_airports_dq ─┐
│ ├─ load_routes → check_routes_dq
└─ load_airplanes → check_airplanes_dq ─┤
└─ load_seats → check_seats_dq
```
- `load_airports_to_stg``check_airports_dq` (`sql/stg/airports_load.sql`, `sql/stg/airports_dq.sql`)
- `load_airplanes_to_stg``check_airplanes_dq` (`sql/stg/airplanes_load.sql`, `sql/stg/airplanes_dq.sql`)
- `load_routes_to_stg``check_routes_dq` (`sql/stg/routes_load.sql`, `sql/stg/routes_dq.sql`)
- `load_seats_to_stg``check_seats_dq` (`sql/stg/seats_load.sql`, `sql/stg/seats_dq.sql`)
- `load_routes_to_stg``check_routes_dq` (`sql/stg/routes_load.sql`, `sql/stg/routes_dq.sql`) — зависит от **airports** и **airplanes** (DQ проверяет ссылочную целостность)
- `load_seats_to_stg``check_seats_dq` (`sql/stg/seats_load.sql`, `sql/stg/seats_dq.sql`) — зависит от **airplanes** (DQ проверяет `airplane_code → airplanes`)
7) Транзакции
- `load_flights_to_stg``check_flights_dq` (инкремент по `scheduled_departure`)
- `load_segments_to_stg``check_segments_dq` (инкремент по `book_date` через tickets/bookings)
- `load_boarding_passes_to_stg``check_boarding_passes_dq` (full snapshot)
- `load_flights_to_stg``check_flights_dq` (инкремент по `scheduled_departure`) — зависит от **routes**
- `load_segments_to_stg``check_segments_dq` (инкремент по `book_date` через tickets/bookings) — зависит от **flights**
- `load_boarding_passes_to_stg``check_boarding_passes_dq` (full snapshot) — зависит от **segments**
Ветка `seats` работает параллельно с веткой `routes → flights → segments → boarding_passes`.
Обе ветки сходятся на `finish_summary`.
Важно: для инкрементальных таблиц “пустое окно инкремента” допустимо — загрузка и DQ логируют `NOTICE` и завершаются успешно.
Для snapshot-справочников (airports/airplanes/routes/seats) пустой источник считается ошибкой (DQ делает `RAISE EXCEPTION`).
8) `finish_summary`
- ждёт завершения **обеих** параллельных веток (`check_boarding_passes_dq` и `check_seats_dq`);
- логирует краткую сводку в конце запуска.
## Как проверить результат