From bca1ffa379ce50faf32b40d5ac8de552541d03cc Mon Sep 17 00:00:00 2001 From: Dmitry Dementiev Date: Fri, 21 Aug 2026 23:38:45 +0300 Subject: [PATCH] =?UTF-8?q?fix(world):=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=8B=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B6?= =?UTF-8?q?=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE=D1=81=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B0=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Зачем: - свежий main добавил мониторинг и проявил устаревшие доводы, мёртвые настройки и слишком короткий тайм-аут DDL. - Что: - документация приведена к текущему жизненному циклу мира и составу стенда; - удалены лишняя проверка и неиспользуемый YAML-якорь; - ожидание ClickHouse возвращено к 300 секундам, а отказы и параметры DockerOperator пояснены. - Проверка: - `make config-test`; - `make lint`; - `make smoke` — 21/21. --- README.md | 4 ++-- compose.yaml | 4 ---- dags/world_lifecycle.py | 11 ++++++++-- docs/adr/0001-stand-services.md | 6 ++++++ docs/architecture/monitoring/cluster.md | 6 ++++-- docs/architecture/testing.md | 28 ++++++++++++++----------- docs/specs/2026-08-01-generator.md | 15 ++++++------- scripts/config-test.sh | 5 ----- 8 files changed, 45 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 46ba54a..f1f0502 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,8 @@ make check-services `superset-init` завершаются с кодом 0. Первый обновляет схему Airflow, подготавливает администратора и два подключения к `clickhouse-01`. Второй обновляет Superset, создаёт администратора и импортирует подключение к -`clickhouse-02`. -С нуля подъём занимает около трёх минут, на живом стенде — около минуты. +`clickhouse-02`. На ноутбуке в режиме энергосбережения приёмочный подъём с +пустых томов занял около десяти минут, повторный на живом стенде — около трёх. `make smoke` за секунды спрашивает, собран ли стенд: зависимости машины, здоровье контейнеров, устройство keeper, ответ Kafka с машины через отображённый diff --git a/compose.yaml b/compose.yaml index 0f58f01..5f21f01 100644 --- a/compose.yaml +++ b/compose.yaml @@ -46,10 +46,6 @@ x-kafka-target: &kafka-target <<: *kafka-common 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-airflow-common: &airflow-common diff --git a/dags/world_lifecycle.py b/dags/world_lifecycle.py index 16f6d2b..492ec04 100644 --- a/dags/world_lifecycle.py +++ b/dags/world_lifecycle.py @@ -56,7 +56,9 @@ def _clickhouse_client(): password=connection.password, database=connection.schema or "default", 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_TOPIC": HITS_TOPIC, }, + # Вывод уже переехал в журнал задачи; завершённый контейнер не нужен. auto_remove="force", + # Временный путь Airflow существует внутри контейнера, но монтировать + # его пытается хостовый Docker. Генератору этот каталог не нужен. mount_tmp_dir=False, ) @@ -260,7 +265,9 @@ def world_initialize(): finally: client.close() raise AirflowException( - f"стартовый мир не принят за 300 с: строк {arrived} из {expected}" + f"стартовый мир не принят за 300 с: строк {arrived} из {expected}; " + "проверьте журнал send_initial_events и " + "SELECT * FROM system.kafka_consumers" ) @task diff --git a/docs/adr/0001-stand-services.md b/docs/adr/0001-stand-services.md index a4f186d..4586a4d 100644 --- a/docs/adr/0001-stand-services.md +++ b/docs/adr/0001-stand-services.md @@ -10,6 +10,12 @@ обработчик DAG. Triggerer не запускается: в каркасе нет отложенных задач. Два интеграционных пробника написаны через публичный `airflow.sdk`. +Долгоживущие процессы Airflow зависят от `airflow-init`, а Superset — от +`superset-init`. Это ребро нужно самому `up --wait`: Docker Compose 2.40.3 +считает успешно завершившийся одноразовый сервис без зависимого упавшим и +возвращает единицу — поведение проверено при исполнении #37. Зависимость +включает результат подготовки в общий граф ожидания. + Для входа выбран SimpleAuthManager. У него нет команды создания пользователя, поэтому `airflow-init` записывает пароль администратора из окружения в JSON-файл отдельного тома `airflow_auth`. Новый именованный том принадлежит diff --git a/docs/architecture/monitoring/cluster.md b/docs/architecture/monitoring/cluster.md index 5fe9547..345cdbf 100644 --- a/docs/architecture/monitoring/cluster.md +++ b/docs/architecture/monitoring/cluster.md @@ -144,8 +144,10 @@ Keeper — отдельный сервис, системных таблиц у вышло восемь: четыре таблицы, каждая обеими нодами. Таблиц ошибок среди них нет, и это правда состояния — частей у них пока не появилось. - Очередь DDL показала `CREATE MATERIALIZED VIEW ... ON CLUSTER` в состоянии - `Finished` и со временем по каждой ноде: `make generate-batch` поднимает - `clickhouse-init`, и тот заново прогоняет DDL. + `Finished` и со временем по каждой ноде. Новые безопасные записи для показа + оставляет `make check-clickhouse`: цель создаёт и удаляет временные таблицы + `ON CLUSTER`. Канонический DDL появляется в очереди при создании мира дагом + `world_initialize`. Подписи рядов (`${__field.labels.node}`) и правило, по которому пунктирным становится только ряд «отведено», сверены по документации Grafana через MCP diff --git a/docs/architecture/testing.md b/docs/architecture/testing.md index 7790713..cac78c3 100644 --- a/docs/architecture/testing.md +++ b/docs/architecture/testing.md @@ -241,22 +241,26 @@ Kafka → STG → ODS, и живёт он в `make check-clickhouse`. 19/2: назвал нездоровый сервис и отсутствие одной из четырёх целей. После возврата сервиса прогон снова дал 21/21. -**Приёмка #119 21 августа 2026 года.** `make rebuild-storage` через Airflow -прошёл за 3 м 9 с: позиция прошла задачи `-1` → `0` → `8`, топики получили -новые идентификаторы, группы дочитали новые топики без отставания, а ODS принял -401 185 событий без брака и 2 851 актуальный заказ. Повторный `make up` занял -2 м 41 с вместе со штатным повторным запуском служб инициализации; -`world_initialize` завершился за один цикл опроса и оставил счётчики -неизменными. Отдельно -проверены красные отказы `world_initialize` при `-1` и `world_next_day` при -отсутствующей позиции, `0` и `-1`; `lifecycle` отказано в чтении -`system.users`, но разрешено чтение `system.settings`. +После переноса #119 поверх этого состава повторный `make up` сохранил готовый +мир, смоук прошёл 21/21, проверка ClickHouse — 10/10, межсервисная — 7/7. + +**Приёмка логики #119 до переноса поверх мониторинга 21 августа 2026 года.** +`make rebuild-storage` через Airflow прошёл за 3 м 9 с: позиция прошла задачи +`-1` → `0` → `8`, топики получили новые идентификаторы, группы дочитали новые +топики без отставания, а ODS принял 401 185 событий без брака и 2 851 +актуальный заказ. Задача `build_generator_image` заняла по 1,5 с в двух +прогонах. +Повторный `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 clean`. Даг создал отсутствующую позицию и закончил на `8`; ODS снова получил 401 185 событий без брака и 2 851 заказ. У `hits` два раздела, у -`orders` один, отставание обеих групп равно нулю. На этом стенде прошли смоук -20/20, проверка ClickHouse 10/10 и межсервисная проверка 7/7. +`orders` один, отставание обеих групп равно нулю. На тогдашнем составе стенда +прошли смоук 20/20, проверка ClickHouse 10/10 и межсервисная проверка 7/7. Оборванную очистку проверили после записи `world_position=-1`: остановили первую ноду ClickHouse, и `world_recreate` покраснел на удалении баз. Следующий diff --git a/docs/specs/2026-08-01-generator.md b/docs/specs/2026-08-01-generator.md index aa1ae61..6e780b5 100644 --- a/docs/specs/2026-08-01-generator.md +++ b/docs/specs/2026-08-01-generator.md @@ -326,10 +326,10 @@ - **Обрыв любого режима — переигровка дня целиком**; дедуп склеивает повторы: `WatchID` детерминированы, повтор — та же строка для ReplacingMergeTree. -- **Эталонный снимок при старте стенда — через Kafka, пакетным режимом - проигрывателя.** Отдельный механизм заливки не строится: каждый `make up` - бесплатно прогоняет весь конвейер на настоящих данных, и строгий приём - хранилища проверяет контракт тем же прогоном. +- **Эталонный снимок при создании мира — через Kafka, пакетным режимом + проигрывателя.** Отдельный механизм заливки не строится: `world_initialize` + прогоняет весь конвейер на настоящих данных при первом `make up` и при явном + `make rebuild-storage`. На готовом мире повторный `make up` заливку пропускает. Оговорка «если заливка уйдёт в десятки минут — вернуться к прямой загрузке» проверена при фиксации чисел: 14 × 50 тыс. ≈ 700 тыс. событий — расчётно минута-две, запас есть. @@ -361,10 +361,11 @@ окном K = 7, дышащая зона и две волны недельной сезонности. Удлинение до месяца — дешёвый ход (пересборка описи), если понадобится. - **В git — только опись, снимок не хранится.** Снимок генерируется при - `make up` и при проверках: артефакт — кэш чистой функции, кэш в git не - хранят. Опись несёт паспорт мира, счётчики и хеши по дням; проверки + создании мира и в проверках генератора: артефакт — кэш чистой функции, кэш в + git не хранят. Опись несёт паспорт мира, счётчики и хеши по дням; проверки «пустой git diff» и «пересгенерируй день N — сравни хеш» живут на ней. - Каждый `make up` — живая демонстрация детерминизма. Честная потеря — + Первый `make up` пустого стенда — живая демонстрация детерминизма; готовый мир + повторный подъём не пересчитывает. Честная потеря — страховка на случай платформенного бага: раньше менти с расходящимися байтами мог взять готовый снимок из git, теперь он упрётся в красный чек описи; смягчение — CI гоняет генерацию на amd64 и arm64. diff --git a/scripts/config-test.sh b/scripts/config-test.sh index b4209e7..9dde04e 100755 --- a/scripts/config-test.sh +++ b/scripts/config-test.sh @@ -62,11 +62,6 @@ jq -e ' ["kafka-init", "clickhouse-init", "world-init", "world-snapshots"] | all(. as $name | $services | has($name) | not) ' >/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 ' .services["airflow-scheduler"] as $service | ($service.environment.CLICKHOUSE_LIFECYCLE_PASSWORD | length > 0) and