Commit Graph
17 Commits
Author SHA1 Message Date
ddadmin 704c139d5a refactor(compose): отделены локальные настройки от фактов стенда
- Зачем:
  - устранены дублирование значений и тихая подстановка неполной настройки.
- Что:
  - версии образов и внутренняя топология закреплены рядом с местом использования.
  - имя экземпляра, внешние порты, учётные данные и ключи сделаны обязательными настройками .env.
  - быстрый старт, Dockerfile и статическая проверка приведены к новой границе.
- Проверка:
  - make config-test.
  - docker build для образов Airflow и Superset без аргументов.
  - make up; make smoke; make check-clickhouse; make check-services.
2026-08-08 20:50:35 +03:00
ddadmin c696fce40b fix(stand): находки ревью — диагноз не утверждает причину, комментарии не врут
Зачем
Холодное ревью нашло три места, где написанное сильнее сделанного.

Что
- Непустая таблица брака больше не выдаётся за доказательство сломанного
  разбора. Модельного дня у брака нет, обрамить его нечем, и строки прежних
  уроков лежат в нём месяц: после первого же урока с мусором проверка
  давала бы неверный диагноз навсегда. Теперь она даёт признак, по которому
  причину отличают, — сошлась недостача с числом брака или нет.
- Комментарий у world-init обещал, что расхождение числа дней с
  STARTING_DAYS поймают счётчики. Это неправда в одну сторону: лишний день
  ложится за рамкой дат описи. Обещание убрано, дыра названа.
- Довод «даг next_day этапа 5 продолжит ось» опирался на несуществующий
  этап; заменён настоящей причиной — заливка замыкает цепь разовых служб.
- Потолок ожидания 300 с получил обоснование замером с кратностью, а сам
  скрипт — честную оговорку: его обещание работает на пустом стенде, на
  живом ждать нечего.
- Третья, пропущенная ссылка на снятый порог скорости дня убрана из спеки.
- Даты замеров в карте целей разведены: #42 менял три цели, а не шесть.

Проверка
Обе ветви диагноза сняты заново на живом стенде: без брака — «не доехали»,
с браком — признак различения. Стенд восстановлен, все 9 проверок зелёные,
брака 0. make lint, typecheck, config-test, test (407 тестов) зелёные.

Ссылка: #42
2026-08-07 18:47:13 +03:00
ddadmin 7c9eeedc40 feat(stand): make up наполняет стенд стартовым миром, опись сторожит его
Зачем
Стенд поднимался пустым, и всякая приёмка следующих этапов начиналась с
ручной заливки данных. Теперь `make up` сам приводит стенд к одному и тому
же состоянию, а в git лежит то, чем это состояние проверяется.

Что
- Опись мира `data/world-inventory.json`: паспорт (зерно, версия
  генератора, хеш каталога) и по строке на каждый из восьми дней — дата,
  число событий, хеш байтов. Собирается `make inventory`, свежесть сторожит
  `test_inventory.py` — тем же способом, что свежесть описания выгрузки.
- Разовая служба `world-init` вышла из-под профиля и играет в топик восемь
  дней при каждом подъёме; зависимый у неё — `airflow-init`, иначе `--wait`
  считает успешно отработавшую службу упавшей.
- `scripts/wait-for-world.sh` — вторая половина `make up`: приём
  асинхронный, поэтому ждать надо доезда до `ods.event`, а не завершения
  заливки. Ограниченный цикл опроса, не пауза наугад.
- Девятая проверка `make check-clickhouse`: подневный счёт событий против
  описи, рамка по датам стартового мира, счёт через `FINAL`. При
  расхождении называет, где искать, — в событиях или в браке.
- Порог «день ≤ 30 с» снят из спеки генератора в обоих местах: замер дал
  1,7 с, порог был выше факта в восемнадцать раз. На его месте — замеры с
  датой. Раздел 9 спеки закрыт: открытых вопросов не осталось.
- Слова: «манифест» стал описью мира, «зерновой мир» — стартовым миром
  (решение владельца). Оба заведены в словарь CONTEXT.md.

Проверка
`make clean && make up` с нуля — 2 м 50 с, доехало ровно 401 185 событий.
`make check-clickhouse` зелёный (8 с), `make smoke` зелёный (9 с),
`make test` — 407 тестов за 71 с, `make lint`, `make typecheck`,
`make config-test` зелёные.

Что проверка умеет краснеть, снято двумя поломками: снос партиции
2026-06-03 дал диагноз «не доехали до ODS», негодная строка в сырье —
«сломан разбор». Строки опыта убраны, день переигран, счёт вернулся.
Тест свежести проверен молчаливой правкой цены в каталоге: покраснел.

Ссылка: #42
2026-08-07 18:37:01 +03:00
ddadminandClaude Opus 5 d7485217d8 refactor(scripts): clickhouse-smoke.sh переименован в check-clickhouse.sh
Зачем: имя файла осталось от прежней цели smoke-cluster, которой больше нет,
и читатель ищет проверку ClickHouse не там, где она лежит.

Что: git mv scripts/clickhouse-smoke.sh scripts/check-clickhouse.sh, тем же
коммитом — вызов в Makefile и строка в карте целей. Абзац-объяснение в
docs/architecture/testing.md снят: он обещал переименование, которое здесь и
случилось.

Проверка: make check-clickhouse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:33:44 +03:00
ddadminandClaude Opus 5 a61f7934ec feat(generator): сериализатор, приёмники, проигрыватель и запуск контейнером
- Зачем:
  - до сих пор генератор умел собирать день, но не умел его отдать: топик
    hits наполнялся пробником, а не настоящими данными. Тикет #41 доводит
    события до стенда и закрывает форму на проводе, на которую обопрётся
    типизированный ODS (#43).
  - сериализатор один по решению спеки: второе место, печатающее событие в
    JSON, разошлось бы с первым молча.
- Что:
  - serialize.py — канонический сериализатор на orjson: единственное место,
    где событие целиком становится JSON; 47 ключей всегда, «пусто» это
    пустое значение, даты ISO-8601, ecommerce строкой. Вложенный блок
    ecommerce в commerce.py вторым сериализатором не считается — правило
    про событие, а не про блок внутри него.
  - sinks.py — приёмники: файл (одно событие — одна строка) и Kafka (одно
    событие — одно сообщение). Ключа у сообщения нет: WatchID уникален,
    ключом он был бы ключом лишь на вид.
  - player.py, cli.py — проигрыватель и интерфейс запуска: режимы batch и
    live (темп ×60), несколько дней одним запуском, ограниченная пачка,
    раздельные тайминги генерации и доставки, лаг в логе.
  - день на оси и имя топика умолчаний не имеют: параметр, описывающий
    среду или позицию, приходит от зовущего, иначе отказ до генерации.
    Умолчания зерна, числа дней и темпа остаются — они описывают мир.
  - generator/Dockerfile — свой образ: зависимости из uv.lock, база
    закреплена до патча, раскладка репозитория сохранена ради каталога
    товаров. Образ Airflow не тронут.
  - разовая служба compose под профилем, цели generate-batch и
    generate-live, .dockerignore, tmp/ в .gitignore.
  - решения внесены в спеку (разделы 4, 8, 9), быстрый старт — в README.
- Проверка:
  - make test 406 passed, make lint, make typecheck, make config-test.
  - побайтовый детерминизм: два прогона дня в независимых процессах дают
    один sha256; день в контейнере совпадает с днём на машине.
  - на стенде: пакетный день доехал до stg.hits_raw_dist, счёт по
    Distributed сошёлся — отправлено 50626, в таблице 50626.
  - топик прочитан обеими нодами: clickhouse-01 раздел 0 (26368),
    clickhouse-02 раздел 1 (24258).
  - живой день: модельное время 01:00 на 60-й секунде, 02:00 на 120-й —
    темп ×60, лаг печатается.
  - форма на проводе в колонке raw: даты читаются глазами, ecommerce лежит
    строкой.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:05:11 +03:00
ddadminandClaude Opus 5 5492e6ff3d refactor(config-test): срезан разбор Bash — он не ловил ничего
- Зачем:
  - проверка была сломана с рождения цели: bash -n со списком файлов
    разбирает только первый, остальные уходят ему в аргументы. Из пяти
    скриптов проверялся один, и за всё время этого никто не заметил.
  - чинить незачем: скрипты стенда запускают с той же машины, и
    синтаксическая ошибка вылезает при первом же запуске с номером строки.
    Учебной ценности в проверке нет — из неё не узнаёшь ничего, кроме того,
    что у bash есть ключ -n.
  - держалась она не строчкой, а двенадцатью: обход репозитория, временный
    файл со списком, mapfile и две ветки на пустой список.
- Что:
  - из scripts/config-test.sh убраны разбор Bash и весь аппарат сбора
    списка файлов; 53 строки стали 40.
  - разбор файлов DAG остался и получил комментарий с основанием: их на
    машине не запускает никто, обработчик разбирает их внутри контейнера, и
    ошибка всплывает не сообщением, а молча пропавшим DAG.
  - README и карта проверок больше не обещают проверку синтаксиса Bash.
  - в карте записано, почему проверку не стоит заводить заново.
- Проверка:
  - make config-test зелёный.
  - оставшийся разбор DAG краснеет: незакрытая скобка в dags/test_kafka.py
    роняет цель с SyntaxError и ненулевым кодом; файл восстановлен.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 16:59:44 +03:00
ddadminandClaude Opus 5 7e4d5815a3 feat(smoke): смоук спрашивает Kafka снаружи — по объявленному адресу
- Зачем:
  - деление целей оставило дыру: про Airflow, Superset, Prometheus и Grafana
    смоук стучится с машины в отображённый порт, а про Kafka после переезда
    check_kafka_from_host знал только «контейнер здоров».
  - вердикт этот приходит из healthcheck в compose.yaml, а тот спрашивает
    брокер изнутри и по внутреннему слушателю: объявленный наружу адрес может
    вести не туда, и Kafka всё равно останется здоровой.
  - поломка популярная и показательная: клиент подключается, получает
    метаданные и молча виснет на адресе, которого с его стороны нет. Менти
    узнаёт, что у брокера два слушателя и зачем нужен advertised.listeners.
    Генератор будет писать в Kafka именно с машины.
- Что:
  - check_kafka_external_listener в make smoke: запрос списка топиков с машины
    через отображённый порт, ответ приходит только если объявленный адрес ведёт
    туда же. Комментарий у проверки объясняет, от чего она заведена.
  - ожидание ответа ограничено 15 секундами при замеренных 2,6 — впятеро
    больше, чем стоит зелёный прогон.
  - README и карта проверок: новая проверка названа, доводы записаны, цена
    смоука обновлена с 6 до 8 секунд.
- Проверка:
  - make config-test, make smoke (20 проверок, 8 с), make check-clickhouse,
    make check-services — зелёные.
  - краснеет на своей поломке: брокеру объявлен адрес kafka-nowhere:29092 при
    целом внутреннем слушателе — проверка состояния контейнера осталась
    зелёной, смоук покраснел именно на этой строке. После проверки Kafka
    возвращена в исходное состояние, посторонних контейнеров не осталось.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 15:20:27 +03:00
ddadminandClaude Opus 5 bbbe17cfb0 refactor(smoke): цели проверки по назначению — смоук, ClickHouse, службы
- Зачем:
  - смоук перестал быть быстрым: 42 секунды из 48 съедали шесть проверок,
    которые ждут службу — запуск DAG, вход в Superset, Kafka с машины.
  - имена целей врали: смоуком звались и глубокая проверка кластера, и
    интеграционные проверки; префикс достался им от общего происхождения.
  - нигде не было записано, зачем в репозитории каждая цель и куда класть
    новую проверку, — без записи скрипт дорастёт снова.
- Что:
  - ось деления — кого спрашивают, а не сколько стоит: make smoke (стенд
    собран), make check-clickhouse (спрашивают у ClickHouse), новая
    make check-services (службы работают).
  - шесть тяжёлых проверок переехали в scripts/stand-services.sh; общее —
    счёт, обращение к Compose, зависимости машины и check_containers_survived
    — вынесено в scripts/stand-common.sh, копипасты нет.
  - smoke-cluster переименована в check-clickhouse; имя файла скрипта не
    тронуто (в него встраивается проверка договора со схемой), расхождение
    названо в карте.
  - смоук и check-services печатают своё время в строке ИТОГ; порога по
    времени нет — по доводу ADR 0004.
  - docs/architecture/testing.md: карта всех семи целей, правило быстрого
    смоука словами, лесенка по частоте и правило про краснеющую проверку,
    переехавшее из README; указатель из AGENTS.md.
  - README: описания целей сокращены, карта не дублируется; быстрый старт
    показывает работающий стенд, а не только собранный.
  - планка приёмки этапа в спеке названа поимённо: три цели вместо
    «smoke-проверки».
- Проверка:
  - make config-test, make smoke (19 проверок, 6 с), make check-clickhouse
    (8 проверок, 7 с), make check-services (7 проверок, 44 с) — зелёные.
  - 19 + 7 = 25 разных проверок, как и до деления: check_containers_survived
    считается дважды намеренно.
  - краснеют обе разделённые цели: со снятым prometheus смоук дал три ошибки,
    с подменённым UUID подключения Superset покраснел check-services.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 14:34:02 +03:00
ddadmin a2f5b27d89 refactor(smoke): ограничен по времени опрос keeper, уточнены формулировки
- Зачем:
  - горячее ревью: перевезённая проверка keeper потеряла привычку файла
    ограничивать обращения к контейнерам по времени и глушить их ошибки.
- Что:
  - опрос keeper идёт через keeper_exec с timeout 20s и тихим stderr,
    в отчёте об отказе пустой ответ назван словами.
  - комментарий к проверке и абзац README переписаны на проверяемое
    утверждение: настройки объявлены в compose.yaml, смоук спрашивает,
    дошли ли они до процесса.
  - в пробнике ClickHouse ожидаемой строке возвращено имя expected_rows.
- Проверка:
  - make config-test, make smoke, make smoke-cluster; отдельно проверено,
    что на паузе keeper проверка краснеет, а не виснет.
2026-08-06 14:01:45 +03:00
ddadmin 66490d124e refactor(smoke): срезаны проверки стенда, не служащие менти
- Зачем:
  - проверок стало больше, чем продукта, и росли они из критериев приёмки,
    а не из учебной ценности (#56).
- Что:
  - удалены tests/dag-probes-unit.py, tests/stand-smoke-guards.sh,
    tests/stand-smoke-static.sh и tests/smoke-guards.sh вместе с целью
    make smoke-guards и запуском юнит-тестов в scripts/config-test.sh.
  - из scripts/stand-smoke.sh убран check_env_consistency, туда же переехал
    check_keeper_runtime; счёт проверок остался 25.
  - в пробниках свёрнуты функции _assert_*, комментарий про отложенный импорт
    переписан на причину из документации Airflow и продублирован в test_kafka.
- Проверка:
  - make config-test, make up, make smoke, make smoke-cluster.
2026-08-06 13:06:44 +03:00
ddadminandClaude Opus 5 8778567266 style(stand): комментарии ужаты до того, чего нет в коде
Зачем

Комментарии к правке были размером с объяснение, хотя объяснение уже лежит
в ADR 0004. В compose.yaml четыре строки на одну настройку; в stand-smoke.sh
одиннадцать новых строк там, где на весь файл до этого было две — шебанг и
одна строка про разбор подстановок. Заодно в комментариях остались метафоры
(«бронь», «предохранители»), вычищенные из ADR прошлым коммитом.

Что

- compose.yaml: одна строка вместо четырёх — почему не гигабайт и куда идти
  за подробностями.
- stand-smoke.sh: две строки вместо шести — зачем проверка вообще нужна.
  Комментарий про разбор `--format` убран целиком: он оправдывался перед
  читателем, а не помогал ему.
- Комментарий про OOMKilled оставлен, но в одну строку: без него сообщение
  «убило процесс, а не контейнер» выглядит опиской.

Проверка

make config-test — зелено.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 15:26:22 +03:00
ddadminandClaude Opus 5 5a21684dc4 fix(stand): поправлены находки ревью — причина дрейфа памяти и отзыв довода ADR 0001
Зачем

Двухосевое ревью нашло в PR фактическую ошибку и одну процессную дыру. Ошибка
того же класса, что уже снималась по ходу разбора: в ADR было записано, будто
RSS ноды полз вверх из-за страниц её бинарника. Замер на живой ноде это
опроверг.

Что

- ADR 0004: причина дрейфа переписана по замеру. За обычную сессию страницы
  бинарника 523 -> 531 МиБ, то есть стоят на месте, а рабочая память
  489 -> 723 МиБ. Бинарник объясняет постоянную часть расхода, а не рост;
  отчего растёт рабочая память, для этого решения знать не нужно. Вывод не
  меняется: одна только постоянная часть занимала больше половины гигабайтной
  коробки.
- ADR 0001: ресурсный довод отозван прямо в файле — и строкой статуса, и
  абзацем после самого довода. Обе оси ревью нашли это независимо друг от
  друга: строка «удерживает стенд в пределе 3,4 ГБ» читалась как действующая,
  хотя предела уже нет.
- stand-smoke.sh: OOMKilled поднимается и тогда, когда ядро убило процесс
  внутри живого контейнера, поэтому сообщение говорит про процесс, а не про
  контейнер. Флаг hurt переименован в problems и считает находки — как passed
  и failed по соседству.
- Формулировки ADR 0004 упрощены: «коробка» объясняется при первом упоминании,
  а метафоры «вход в самонастройку», «предохранители», «бронь», «полка» и
  «бюджет в новой одежде» заменены обычными словами. Правило AGENTS.md —
  сложную мысль пояснять при первом упоминании.

Проверка

make config-test — зелено. make smoke — 25 из 25, проверка выживания отработала
с новым сообщением.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 15:18:43 +03:00
ddadminandClaude Opus 5 a9d66ed74a fix(stand): снят несуществующий бюджет памяти, нодам ClickHouse — 4 ГиБ
Зачем

Стенд упирался в память ноды ClickHouse: пробник валился на CREATE TABLE
ON CLUSTER, вместе с ним краснели make smoke и make smoke-guards. Причина не
та, что предполагал #21: дело не в заводских кэшах, а в коробке на гигабайт.
Около 550 МиБ RSS праздной ноды — страницы её собственного бинарника, и на
работу оставалось около 350 МиБ, которые пробник добирал за сессию.

Заодно выяснилось, откуда взялся предел 3,4 ГБ. Это была оценка расхода из
спеки, посчитанная по стенду-предшественнику до первой сборки v2 и превращённая
в жёсткий порог проверки. Порог стал критерием приёмки каждого этапа и дальше
блокировал бы любой рост стенда на этапах 2-9.

Что

- ADR 0004: бюджета памяти у стенда нет, есть требование к машине — около 8 ГБ,
  доступных Docker. Ресурсный довод ADR 0001 отозван, сами решения в силе.
- Нодам ClickHouse 4 ГиБ вместо гигабайта. Остальные лимиты не тронуты: ни один
  из них ни разу не сработал, а снять их скопом — то же изменение без
  свидетельств, каким они были выставлены.
- Из make smoke убрана проверка суммарного потребления. Она мерила docker stats
  вместе со страничным кэшем, то есть отвечала на вопрос «сколько файлов стенд
  потрогал», и с появлением настоящих данных краснела бы на здоровом стенде.
  Вместе с ней убрана привязанная к её сообщению проверка docs-guards.
- Взамен smoke спрашивает у Docker, не убивало ли ядро долгоживущий контейнер
  за память и не включалась ли политика перезапуска. Порога у проверки нет:
  убитый контейнер Docker поднимает сам, и без этого вопроса стенд отрапортует
  «всё хорошо» о ноде, которая умирала.
- README и раздел «Ресурсный бюджет» спеки переписаны с предела на требование
  к машине; README объясняет менти, что такое «память, доступная Docker».

Проверка

make config-test; make up; make smoke — 25 из 25; make smoke-cluster — 8 из 8;
make smoke-guards — 3 из 3, включая шаг «после восстановления стенд проходит
make smoke», который падал 31 июля.

На живом стенде с новой коробкой: max_server_memory_usage = 3,60 ГиБ, в журнале
ноды «Lowered mark cache size to 2.00 GiB because the system has limited RAM».
Семантика счётчиков Docker снята отдельными контейнерами: ручной restart
оставляет RestartCount = 0, убийство за память даёт OOMKilled = true и растущий
счётчик, убийство не за память OOMKilled не поднимает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 14:35:36 +03:00
ddadminandClaude Opus 5 812b398ce2 fix(tests): сторож документации называет непрошедшую проверку, кластерная больше не виснет
Зачем.
Сторож `tests/docs-guards.sh` падал через `set -e`: единственным следом была
единица в коде возврата, а какое именно утверждение о README перестало быть
правдой — не сообщалось. Со стороны файл выглядел набором несвязанных grep
без объяснения, зачем каждый из них нужен.

Отдельно: `make smoke-cluster` мог зависнуть навсегда. У запроса INSERT
clickhouse-client дочитывает данные из стандартного ввода и ждёт его конца;
при запуске не из терминала, а из фонового процесса с открытым вводом конец
не наступает никогда. Проверка молча висела больше двадцати минут.

Что.
- Проверки собраны в именованные функции, каждая с комментарием, зачем она
  существует и что ломается, когда она краснеет.
- Обёртка `check` печатает утверждение и при успехе, и при провале, считает
  пройденные и выходит с понятным сообщением.
- Ввод запросов ClickHouse закрыт через `</dev/null`, рядом — объяснение
  причины.
- README: раздел «Какую проверку когда запускать» — лесенка от дешёвой
  статической проверки к дорогой интеграционной, с ответом, зачем внутри
  `make smoke-guards` три прогона `make smoke`.

Проверка.
make config-test — пройдено 3, 3 и 6, ошибок 0.
Фальсификация сторожа: порт ноды 2 в README изменён — «ОШИБКА: не
подтвердилось: README перечисляет HTTP- и нативные порты обеих нод», код 1;
двоеточие в строке про перезапуск ClickHouse заменено на тире — «ОШИБКА: не
подтвердилось: README требует перезапуск ClickHouse после изменения настройки
метрик», код 1. README восстановлен из индекса.
make smoke-cluster с открытым стандартным вводом — 8 проверок за 7 с; до
починки та же команда висела 23 минуты и была снята вручную.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 14:08:47 +03:00
ddadminandClaude Opus 5 64f3418378 feat(airflow): пробные DAG test_clickhouse и test_kafka вместо демонстрационного
Зачем.
Демонстрационный DAG example_clickstream_hello ничего не проверял: он не
обращался ни к ClickHouse, ни к Kafka, поэтому его зелёный результат ничего
не говорил о стенде. Пробники проверяют связи по-настоящему — и тем же
клиентом, каким будут ходить рабочие DAG.

Что.
- test_clickhouse: пишет строку в ReplicatedMergeTree на ноде 1 и читает её
  с ноды 2 через Distributed. Данные проходят путь «нода 2 → все шарды →
  шард ноды 1», то есть проверяется межшардовое чтение, а не одна нода.
- test_kafka: пишет в постоянный топик сообщение с меткой прогона и
  вычитывает его обратно.
- infra/airflow/Dockerfile: clickhouse-connect 1.6.0 и confluent-kafka
  2.15.0 вшиты в образ, импорт проверяется на сборке — при запуске
  контейнера пакеты не доустанавливаются.
- Проверки: scripts/stand-smoke.sh гоняет оба пробника через API Airflow,
  scripts/config-test.sh разбирает DAG без стенда,
  tests/stand-smoke-guards.sh проверяет красный путь,
  tests/dag-probes-unit.py — модульные проверки разбора.
- README и ADR 0001 обновлены тем же изменением.
- Удалён dags/example_clickstream_hello.py.

Проверка.
make config-test — пройдено 3, 3 и 6, ошибок 0.
make clean; cp .env.example .env; make up — 116 с на чистых томах.
make smoke — пройдено 25, ошибок 0; стенд занимает 2244,0 MiB.
make smoke-cluster — все 8 проверок кластера.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 14:04:19 +03:00
ddadminandClaude Opus 5 63c42bc068 feat(infra): стенд целиком — Kafka, Airflow 3, Superset и мониторинг одной командой
Зачем: рядом с кластером ClickHouse не хватало остальной платформы, а
поднимать её по кускам — значит каждый раз вспоминать порядок. Теперь
`make up` даёт стенд целиком, а `make smoke` честно отвечает, работает он
или нет.

Что:
- Kafka в режиме KRaft (без ZooKeeper), Postgres под метаданные, Airflow
  3.3 четырьмя сервисами и Superset 6.1 с драйверами ClickHouse;
- мониторинг: Prometheus снимает метрики с обеих нод ClickHouse и keeper,
  Grafana получает подготовленный источник данных;
- подключение Airflow ведёт на ноду 1, подключение Superset — на ноду 2:
  ловушка правильных ошибок, забытый `ON CLUSTER` виден в дашборде сам;
- `scripts/stand-smoke.sh` — сквозная проверка из 24 пунктов: топик в
  Kafka, цели Prometheus, запуск примера DAG через API Airflow, проверка
  подключения Superset и расход памяти против порога 3,4 ГБ;
- `make config-test` — статические ворота: Compose, синтаксис Bash и
  Python, стражи README; стражи smoke проверяют, что отчёт краснеет на
  сломанном стенде и зеленеет после восстановления;
- решения записаны в `docs/adr/0001-stand-services.md`, состав стенда и
  порядок работы — в README.

Проверка: на чистых томах `make clean` → `cp .env.example .env` →
`make up` (1 мин 51 с) → `make smoke` — 24 пройдено, 0 ошибок, 2171 MiB.
Перезапуск `make down` → `make up` → `make smoke` — 24/0. Также зелены
`make config-test` (3/0 и 5/0), `make smoke-cluster` (8/8) и
`make smoke-guards` (3/0 и 3/0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 08:46:04 +03:00
ddadmin 2f9bb8700e feat(infra): поднят кластер ClickHouse из двух шардов и keeper
- Зачем:
  - этап 1 спеки требует стенд, поднимаемый одной командой; кластер —
    единственный режим, выключателя «без кластера» нет (issue #12).
- Что:
  - compose.yaml: две ноды ClickHouse и отдельный clickhouse-keeper на
    зафиксированном LTS-образе 26.3.17.56, порты только на 127.0.0.1.
  - infra/clickhouse: общее описание кластера, подключение к keeper и
    отдельные макросы shard и replica для каждой ноды.
  - scripts/clickhouse-smoke.sh: восемь проверок ON CLUSTER от описания
    кластера до удаления временных таблиц, вывод по-русски.
  - tests/smoke-guards.sh: три проверки самой smoke-команды —
    ограниченная аварийная очистка, обработка прерывания, окружение keeper.
  - README.md: быстрый старт, роли нод, обоснование выбора версии.
- Проверка:
  - make up && make smoke && make smoke-guards && make clean
2026-07-30 18:53:14 +03:00