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>
This commit is contained in:
+20
-4
@@ -4,9 +4,11 @@
|
||||
образцу облачной выгрузки Яндекс Метрики. Устройство и принятые решения —
|
||||
спека [«Генератор (этап 2)»](../docs/specs/2026-08-01-generator.md).
|
||||
|
||||
События уже есть: день-функция отдаёт по паре (зерно, D) упорядоченный поток
|
||||
трёх видов — просмотр страницы, корзина, покупка. Клиентская сторона на этом
|
||||
целая; заказы бэкенда и запуск снаружи — за следующими тикетами.
|
||||
События уже есть и уже уезжают: день-функция отдаёт по паре (зерно, D)
|
||||
упорядоченный поток трёх видов — просмотр страницы, корзина, покупка, —
|
||||
канонический сериализатор превращает его в JSON, а проигрыватель гонит в файл
|
||||
или в Kafka. Клиентская сторона на этом целая; заказы бэкенда — за следующими
|
||||
этапами.
|
||||
|
||||
## Как это работает
|
||||
|
||||
@@ -60,6 +62,16 @@ D0 живёт предыстория, поэтому любой день соб
|
||||
Своя случайность, поэтому правка торговли трафик не двигает.
|
||||
- `src/clickstream_generator/ids.py` — номера событий: неповторяющиеся и
|
||||
ниже 2^53. Обещание одно на обе половины дня, поэтому и живёт отдельно.
|
||||
- `src/clickstream_generator/serialize.py` — канонический сериализатор:
|
||||
единственное место, где событие целиком превращается в JSON. Порядок ключей,
|
||||
все 47 колонок всегда и форма на проводе — ISO-8601.
|
||||
- `src/clickstream_generator/sinks.py` — приёмники: файл (одно событие — одна
|
||||
строка) и Kafka (одно событие — одно сообщение). Про содержимое они не
|
||||
знают; там же довод, почему у сообщения нет ключа.
|
||||
- `src/clickstream_generator/player.py` — проигрыватель: гонит дни в приёмник
|
||||
пачкой или с темпом живого дня. Состояния не хранит.
|
||||
- `src/clickstream_generator/cli.py` — интерфейс запуска: параметры
|
||||
аргументами или окружением, логи в стандартный вывод, итог кодом возврата.
|
||||
- `src/clickstream_generator/schema.py` — контракт схемы: чистые данные о
|
||||
колонках выгрузки. Собственность генератора; из него выводятся сам
|
||||
генератор, его валидация и описание выгрузки в доках.
|
||||
@@ -68,10 +80,14 @@ D0 живёт предыстория, поэтому любой день соб
|
||||
из контракта. Документ руками не правят — пересобирают.
|
||||
- `tests/` — инварианты контракта, свежесть описания и обещания мира:
|
||||
чистота от зерна, приток, гарантия двухкуковых пар, форма суточной волны
|
||||
и сборка визитов по задокументированным правилам.
|
||||
и сборка визитов по задокументированным правилам. Там же побайтовое
|
||||
обещание, доведённое до диска: два прогона дня в файл дают тот же файл, а
|
||||
строк в нём ровно столько, сколько событий.
|
||||
|
||||
## Команды
|
||||
|
||||
Проиграть день — [быстрый старт](../README.md#как-позвать-генератор) и `--help`.
|
||||
|
||||
Из корня репозитория:
|
||||
|
||||
- `make test` — тесты генератора;
|
||||
|
||||
Reference in New Issue
Block a user