fix(world): устранены расхождения после переноса на main
- Зачем: - свежий main добавил мониторинг и проявил устаревшие доводы, мёртвые настройки и слишком короткий тайм-аут DDL. - Что: - документация приведена к текущему жизненному циклу мира и составу стенда; - удалены лишняя проверка и неиспользуемый YAML-якорь; - ожидание ClickHouse возвращено к 300 секундам, а отказы и параметры DockerOperator пояснены. - Проверка: - `make config-test`; - `make lint`; - `make smoke` — 21/21.
This commit is contained in:
1 parent
7e6554507a
commit
bca1ffa379
8 files changed
+45
-34
No files matched your search
@@ -69,8 +69,8 @@ make check-services
|
|||||||
`superset-init` завершаются с кодом 0. Первый обновляет схему Airflow,
|
`superset-init` завершаются с кодом 0. Первый обновляет схему Airflow,
|
||||||
подготавливает администратора и два подключения к `clickhouse-01`. Второй
|
подготавливает администратора и два подключения к `clickhouse-01`. Второй
|
||||||
обновляет Superset, создаёт администратора и импортирует подключение к
|
обновляет Superset, создаёт администратора и импортирует подключение к
|
||||||
`clickhouse-02`.
|
`clickhouse-02`. На ноутбуке в режиме энергосбережения приёмочный подъём с
|
||||||
С нуля подъём занимает около трёх минут, на живом стенде — около минуты.
|
пустых томов занял около десяти минут, повторный на живом стенде — около трёх.
|
||||||
|
|
||||||
`make smoke` за секунды спрашивает, собран ли стенд: зависимости машины,
|
`make smoke` за секунды спрашивает, собран ли стенд: зависимости машины,
|
||||||
здоровье контейнеров, устройство keeper, ответ Kafka с машины через отображённый
|
здоровье контейнеров, устройство keeper, ответ Kafka с машины через отображённый
|
||||||
|
|||||||
@@ -46,10 +46,6 @@ x-kafka-target: &kafka-target
|
|||||||
<<: *kafka-common
|
<<: *kafka-common
|
||||||
KAFKA_TOPIC: hits
|
KAFKA_TOPIC: hits
|
||||||
|
|
||||||
x-orders-kafka-target: &orders-kafka-target
|
|
||||||
<<: *kafka-common
|
|
||||||
KAFKA_TOPIC: *orders-topic
|
|
||||||
|
|
||||||
x-world-starting-days: &world-starting-days "8"
|
x-world-starting-days: &world-starting-days "8"
|
||||||
|
|
||||||
x-airflow-common: &airflow-common
|
x-airflow-common: &airflow-common
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ def _clickhouse_client():
|
|||||||
password=connection.password,
|
password=connection.password,
|
||||||
database=connection.schema or "default",
|
database=connection.schema or "default",
|
||||||
connect_timeout=5,
|
connect_timeout=5,
|
||||||
send_receive_timeout=60,
|
# `ON CLUSTER` ждёт хосты до 180 с. Транспорт живёт дольше, чтобы
|
||||||
|
# ClickHouse сам назвал незавершённый хост вместо сетевого тайм-аута.
|
||||||
|
send_receive_timeout=300,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -97,7 +99,10 @@ def _generator(task_id: str, command: list[str]) -> DockerOperator:
|
|||||||
"KAFKA_BOOTSTRAP_SERVERS": KAFKA_BOOTSTRAP_SERVERS,
|
"KAFKA_BOOTSTRAP_SERVERS": KAFKA_BOOTSTRAP_SERVERS,
|
||||||
"KAFKA_TOPIC": HITS_TOPIC,
|
"KAFKA_TOPIC": HITS_TOPIC,
|
||||||
},
|
},
|
||||||
|
# Вывод уже переехал в журнал задачи; завершённый контейнер не нужен.
|
||||||
auto_remove="force",
|
auto_remove="force",
|
||||||
|
# Временный путь Airflow существует внутри контейнера, но монтировать
|
||||||
|
# его пытается хостовый Docker. Генератору этот каталог не нужен.
|
||||||
mount_tmp_dir=False,
|
mount_tmp_dir=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -260,7 +265,9 @@ def world_initialize():
|
|||||||
finally:
|
finally:
|
||||||
client.close()
|
client.close()
|
||||||
raise AirflowException(
|
raise AirflowException(
|
||||||
f"стартовый мир не принят за 300 с: строк {arrived} из {expected}"
|
f"стартовый мир не принят за 300 с: строк {arrived} из {expected}; "
|
||||||
|
"проверьте журнал send_initial_events и "
|
||||||
|
"SELECT * FROM system.kafka_consumers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@task
|
@task
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
обработчик DAG. Triggerer не запускается: в каркасе нет отложенных задач.
|
обработчик DAG. Triggerer не запускается: в каркасе нет отложенных задач.
|
||||||
Два интеграционных пробника написаны через публичный `airflow.sdk`.
|
Два интеграционных пробника написаны через публичный `airflow.sdk`.
|
||||||
|
|
||||||
|
Долгоживущие процессы Airflow зависят от `airflow-init`, а Superset — от
|
||||||
|
`superset-init`. Это ребро нужно самому `up --wait`: Docker Compose 2.40.3
|
||||||
|
считает успешно завершившийся одноразовый сервис без зависимого упавшим и
|
||||||
|
возвращает единицу — поведение проверено при исполнении #37. Зависимость
|
||||||
|
включает результат подготовки в общий граф ожидания.
|
||||||
|
|
||||||
Для входа выбран SimpleAuthManager. У него нет команды создания пользователя,
|
Для входа выбран SimpleAuthManager. У него нет команды создания пользователя,
|
||||||
поэтому `airflow-init` записывает пароль администратора из окружения в
|
поэтому `airflow-init` записывает пароль администратора из окружения в
|
||||||
JSON-файл отдельного тома `airflow_auth`. Новый именованный том принадлежит
|
JSON-файл отдельного тома `airflow_auth`. Новый именованный том принадлежит
|
||||||
|
|||||||
@@ -144,8 +144,10 @@ Keeper — отдельный сервис, системных таблиц у
|
|||||||
вышло восемь: четыре таблицы, каждая обеими нодами. Таблиц ошибок среди них
|
вышло восемь: четыре таблицы, каждая обеими нодами. Таблиц ошибок среди них
|
||||||
нет, и это правда состояния — частей у них пока не появилось.
|
нет, и это правда состояния — частей у них пока не появилось.
|
||||||
- Очередь DDL показала `CREATE MATERIALIZED VIEW ... ON CLUSTER` в состоянии
|
- Очередь DDL показала `CREATE MATERIALIZED VIEW ... ON CLUSTER` в состоянии
|
||||||
`Finished` и со временем по каждой ноде: `make generate-batch` поднимает
|
`Finished` и со временем по каждой ноде. Новые безопасные записи для показа
|
||||||
`clickhouse-init`, и тот заново прогоняет DDL.
|
оставляет `make check-clickhouse`: цель создаёт и удаляет временные таблицы
|
||||||
|
`ON CLUSTER`. Канонический DDL появляется в очереди при создании мира дагом
|
||||||
|
`world_initialize`.
|
||||||
|
|
||||||
Подписи рядов (`${__field.labels.node}`) и правило, по которому пунктирным
|
Подписи рядов (`${__field.labels.node}`) и правило, по которому пунктирным
|
||||||
становится только ряд «отведено», сверены по документации Grafana через MCP
|
становится только ряд «отведено», сверены по документации Grafana через MCP
|
||||||
|
|||||||
@@ -241,22 +241,26 @@ Kafka → STG → ODS, и живёт он в `make check-clickhouse`.
|
|||||||
19/2: назвал нездоровый сервис и отсутствие одной из четырёх целей. После
|
19/2: назвал нездоровый сервис и отсутствие одной из четырёх целей. После
|
||||||
возврата сервиса прогон снова дал 21/21.
|
возврата сервиса прогон снова дал 21/21.
|
||||||
|
|
||||||
**Приёмка #119 21 августа 2026 года.** `make rebuild-storage` через Airflow
|
После переноса #119 поверх этого состава повторный `make up` сохранил готовый
|
||||||
прошёл за 3 м 9 с: позиция прошла задачи `-1` → `0` → `8`, топики получили
|
мир, смоук прошёл 21/21, проверка ClickHouse — 10/10, межсервисная — 7/7.
|
||||||
новые идентификаторы, группы дочитали новые топики без отставания, а ODS принял
|
|
||||||
401 185 событий без брака и 2 851 актуальный заказ. Повторный `make up` занял
|
**Приёмка логики #119 до переноса поверх мониторинга 21 августа 2026 года.**
|
||||||
2 м 41 с вместе со штатным повторным запуском служб инициализации;
|
`make rebuild-storage` через Airflow прошёл за 3 м 9 с: позиция прошла задачи
|
||||||
`world_initialize` завершился за один цикл опроса и оставил счётчики
|
`-1` → `0` → `8`, топики получили новые идентификаторы, группы дочитали новые
|
||||||
неизменными. Отдельно
|
топики без отставания, а ODS принял 401 185 событий без брака и 2 851
|
||||||
проверены красные отказы `world_initialize` при `-1` и `world_next_day` при
|
актуальный заказ. Задача `build_generator_image` заняла по 1,5 с в двух
|
||||||
отсутствующей позиции, `0` и `-1`; `lifecycle` отказано в чтении
|
прогонах.
|
||||||
`system.users`, но разрешено чтение `system.settings`.
|
Повторный `make up` занял 2 м 41 с вместе со штатным повторным запуском служб
|
||||||
|
инициализации; `world_initialize` завершился за один цикл опроса и оставил
|
||||||
|
счётчики неизменными. Отдельно проверены красные отказы `world_initialize` при
|
||||||
|
`-1` и `world_next_day` при отсутствующей позиции, `0` и `-1`; `lifecycle`
|
||||||
|
отказано в чтении `system.users`, но разрешено чтение `system.settings`.
|
||||||
|
|
||||||
Итоговый холодный `make up` из пустых томов занял 9 м 39 с после 25 с на
|
Итоговый холодный `make up` из пустых томов занял 9 м 39 с после 25 с на
|
||||||
`make clean`. Даг создал отсутствующую позицию и закончил на `8`; ODS снова
|
`make clean`. Даг создал отсутствующую позицию и закончил на `8`; ODS снова
|
||||||
получил 401 185 событий без брака и 2 851 заказ. У `hits` два раздела, у
|
получил 401 185 событий без брака и 2 851 заказ. У `hits` два раздела, у
|
||||||
`orders` один, отставание обеих групп равно нулю. На этом стенде прошли смоук
|
`orders` один, отставание обеих групп равно нулю. На тогдашнем составе стенда
|
||||||
20/20, проверка ClickHouse 10/10 и межсервисная проверка 7/7.
|
прошли смоук 20/20, проверка ClickHouse 10/10 и межсервисная проверка 7/7.
|
||||||
|
|
||||||
Оборванную очистку проверили после записи `world_position=-1`: остановили
|
Оборванную очистку проверили после записи `world_position=-1`: остановили
|
||||||
первую ноду ClickHouse, и `world_recreate` покраснел на удалении баз. Следующий
|
первую ноду ClickHouse, и `world_recreate` покраснел на удалении баз. Следующий
|
||||||
|
|||||||
@@ -326,10 +326,10 @@
|
|||||||
- **Обрыв любого режима — переигровка дня целиком**; дедуп склеивает
|
- **Обрыв любого режима — переигровка дня целиком**; дедуп склеивает
|
||||||
повторы: `WatchID` детерминированы, повтор — та же строка для
|
повторы: `WatchID` детерминированы, повтор — та же строка для
|
||||||
ReplacingMergeTree.
|
ReplacingMergeTree.
|
||||||
- **Эталонный снимок при старте стенда — через Kafka, пакетным режимом
|
- **Эталонный снимок при создании мира — через Kafka, пакетным режимом
|
||||||
проигрывателя.** Отдельный механизм заливки не строится: каждый `make up`
|
проигрывателя.** Отдельный механизм заливки не строится: `world_initialize`
|
||||||
бесплатно прогоняет весь конвейер на настоящих данных, и строгий приём
|
прогоняет весь конвейер на настоящих данных при первом `make up` и при явном
|
||||||
хранилища проверяет контракт тем же прогоном.
|
`make rebuild-storage`. На готовом мире повторный `make up` заливку пропускает.
|
||||||
Оговорка «если заливка уйдёт в десятки минут — вернуться к прямой
|
Оговорка «если заливка уйдёт в десятки минут — вернуться к прямой
|
||||||
загрузке» проверена при фиксации чисел: 14 × 50 тыс. ≈ 700 тыс. событий —
|
загрузке» проверена при фиксации чисел: 14 × 50 тыс. ≈ 700 тыс. событий —
|
||||||
расчётно минута-две, запас есть.
|
расчётно минута-две, запас есть.
|
||||||
@@ -361,10 +361,11 @@
|
|||||||
окном K = 7, дышащая зона и две волны недельной сезонности. Удлинение до
|
окном K = 7, дышащая зона и две волны недельной сезонности. Удлинение до
|
||||||
месяца — дешёвый ход (пересборка описи), если понадобится.
|
месяца — дешёвый ход (пересборка описи), если понадобится.
|
||||||
- **В git — только опись, снимок не хранится.** Снимок генерируется при
|
- **В git — только опись, снимок не хранится.** Снимок генерируется при
|
||||||
`make up` и при проверках: артефакт — кэш чистой функции, кэш в git не
|
создании мира и в проверках генератора: артефакт — кэш чистой функции, кэш в
|
||||||
хранят. Опись несёт паспорт мира, счётчики и хеши по дням; проверки
|
git не хранят. Опись несёт паспорт мира, счётчики и хеши по дням; проверки
|
||||||
«пустой git diff» и «пересгенерируй день N — сравни хеш» живут на ней.
|
«пустой git diff» и «пересгенерируй день N — сравни хеш» живут на ней.
|
||||||
Каждый `make up` — живая демонстрация детерминизма. Честная потеря —
|
Первый `make up` пустого стенда — живая демонстрация детерминизма; готовый мир
|
||||||
|
повторный подъём не пересчитывает. Честная потеря —
|
||||||
страховка на случай платформенного бага: раньше менти с расходящимися
|
страховка на случай платформенного бага: раньше менти с расходящимися
|
||||||
байтами мог взять готовый снимок из git, теперь он упрётся в красный чек
|
байтами мог взять готовый снимок из git, теперь он упрётся в красный чек
|
||||||
описи; смягчение — CI гоняет генерацию на amd64 и arm64.
|
описи; смягчение — CI гоняет генерацию на amd64 и arm64.
|
||||||
|
|||||||
@@ -62,11 +62,6 @@ jq -e '
|
|||||||
["kafka-init", "clickhouse-init", "world-init", "world-snapshots"] |
|
["kafka-init", "clickhouse-init", "world-init", "world-snapshots"] |
|
||||||
all(. as $name | $services | has($name) | not)
|
all(. as $name | $services | has($name) | not)
|
||||||
' >/dev/null <<<"$config_json"
|
' >/dev/null <<<"$config_json"
|
||||||
jq -e '
|
|
||||||
.services.generator as $generator |
|
|
||||||
((($generator.depends_on // {}) | has("kafka-init")) | not) and
|
|
||||||
((($generator.depends_on // {}) | has("clickhouse-init")) | not)
|
|
||||||
' >/dev/null <<<"$config_json"
|
|
||||||
jq -e '
|
jq -e '
|
||||||
.services["airflow-scheduler"] as $service |
|
.services["airflow-scheduler"] as $service |
|
||||||
($service.environment.CLICKHOUSE_LIFECYCLE_PASSWORD | length > 0) and
|
($service.environment.CLICKHOUSE_LIFECYCLE_PASSWORD | length > 0) and
|
||||||
|
|||||||
Reference in new issue
Block a user