feat(etl): добавлен дневной конвейер трансформаций

Зачем:
- Один запуск должен одинаково работать из жизненного цикла, вручную после разгона и повторно после отказа.

Что:
- Добавлена последовательная сцепка DDS и DM с ожиданием каждого слоя.
- DDS дожидается смещений Kafka и очереди доставки ClickHouse за общий срок.
- ETL встроен в создание мира и живой день; документация приведена к новому графу.

Проверка:
- make config-test; make lint.
- make smoke: 21/21; make check-clickhouse: 10/10; make check-services: 7/7.
- make rebuild-storage, живой и пакетный дни, искусственный отказ и ручное восстановление ETL.
This commit is contained in:
ddadmin committed 2026-08-27 02:43:29 +03:00
1 parent fb00bbe4c3
commit 12a5c109b2
10 files changed
+359 -43

No files matched your search

+27 -14
View File
@@ -20,8 +20,9 @@ DDL и двумя одноразовыми службами заливал во
**Чему учит переезд.** Менти видит один наблюдаемый граф, которому принадлежат
прикладная схема, данные мира и позиция модельного времени, — и Compose,
который держит только инфраструктуру. Зелёный `world_initialize` значит ровно
одно: схема создана, оба источника приняты, следующий день известен.
который держит только инфраструктуру. Зеленая ветка создания в
`world_initialize` подтверждает: схема создана, оба источника приняты,
следующий день известен, слои DDS и DM собраны.
## Решение
@@ -106,11 +107,16 @@ Kafka, `SQLExecuteQueryOperator` для исполняемых SQL-файлов
приехало» условием не считается.
7. Отправляет слепки заказов вторым прогоном образа — со сдвигом, дни 0…6
([заказы в стартовом мире](../architecture/orders/start-world.md)).
8. Дёргает `orders_ingest` ждущим триггером и зеленеет только вслед за ним.
9. Последней успешной задачей ставит позицию в `WORLD_STARTING_DAYS`.
8. Дергает `orders_ingest` ждущим триггером и продолжает только после его
успеха.
9. Ставит позицию в `WORLD_STARTING_DAYS`: источники приняты, мир уже создан.
10. Последним шагом дергает `etl_pipeline` ждущим триггером. Конвейер
последовательно ждет `dds_transform` и `dm_transform`; отказ слоя красит
инициализацию.
Порядок задач связывает проверки: каждый шаг подтверждён предыдущим, а красная
задача называет место остановки.
задача называет место остановки. Ветка "мир уже существует" конвейер не
запускает: обычный повтор `make up` по-прежнему ничего не меняет.
### `world_recreate` — снести мир и создать заново
@@ -163,9 +169,15 @@ Kafka, `SQLExecuteQueryOperator` для исполняемых SQL-файлов
недействителен и пересборку надо повторить. Стенд обязан назвать незавершённую
очистку вслух и не продолжать работу молча.
**Очистка прошла, потомок не доработал.** Позиция остаётся `0`. Инициализация
детерминирована, поэтому следующий `make up` просто пробует её заново — с
того же места и с тем же результатом.
**Очистка прошла, создание остановилось до установки позиции.** Позиция
остаётся `0`. Инициализация детерминирована, поэтому следующий `make up` просто
пробует её заново — с того же места и с тем же результатом.
**ETL упал после установки позиции.** Мир и оба источника уже готовы, поэтому
позиция остается в `WORLD_STARTING_DAYS`. После исправления запускают рукой
`etl_pipeline`: он сам выводит объем из состояния данных. Повторный
`world_initialize` здесь не поможет: при готовой позиции инициализация уйдет в
короткую ветку без изменений.
**Позицию в `WORLD_STARTING_DAYS` ставит только успех обоих источников.**
События доехали, слепки приняты, `orders_ingest` зелёный — тогда и только тогда
@@ -181,10 +193,11 @@ ODS истинно сразу — этим оно и ограничено, об
заливка» ни один счёт дать не может. Сторожа на этот случай нет: ошибку менти
делает себе сам и тут же видит.
**Слоты Airflow.** Их четыре, и вложенные ожидания в них укладываются, пока
пересборка не наложилась на движение мира: `world_recreate` ждёт
`world_initialize`, тот ждёт `orders_ingest` — три слота из четырёх. Одновременно
работающий выключатель добавляет свои и загоняет стенд в тупик ожиданий.
**Слоты Airflow.** Их четыре. При пересборке `world_recreate` ждет
`world_initialize`, тот ждет `etl_pipeline`, а конвейер ждет слой. В живом
режиме такую же цепочку образуют `world_live`, `world_live_day`, `etl_pipeline`
и слой. В обоих случаях три ожидающие задачи оставляют слою последний слот.
Одновременная пересборка добавляет ожидания и загоняет стенд в тупик.
Поэтому пересборка — явная операция обслуживания: оператор ставит `world_live`
на паузу и даёт работникам доиграть. Предусловие остаётся в документации;
механизм блокировок стоил бы дороже этой строки.
@@ -214,8 +227,8 @@ ODS истинно сразу — этим оно и ограничено, об
мир уже есть.
- **`make rebuild-storage`** возвращает канонический мир: позиция проходит
`-1` → `0` → `WORLD_STARTING_DAYS`, в ODS ровно даты описи, топики созданы
заново, офсеты групп идут с нуля. Цена прогона называется числом и сверяется
с прежними 2 м 25 с.
заново, офсеты групп идут с нуля, DDS и DM собраны. Время прогона измеряется
заново.
- **Красные пути проверяются своими отказами.** Сторож работника при
отсутствующей, нулевой и отрицательной позиции; `world_initialize` на `-1`;
оборванная очистка, оставляющая `-1`. Проверка, не видевшая своей поломки,