- Зачем: - перед активными визитами нужно отделить генеративную модель от Kafka, состояния и сервисного цикла. - Что: - перенесены модули генератора в пакет `src/clickstream_generator`. - `generator.py` оставлен фасадом и точкой входа с совместимыми импортами. - обновлены Dockerfile, тесты, README, спека и issue 02.5. - Проверка: - `docker build -t generator:test generator`. - `docker run --rm -v /home/dmitry/sources/clickstream-ch-kafka-superset-demo:/workspace -w /workspace/generator generator:test pytest tests/ -q`. - `python -m py_compile generator.py src/clickstream_generator/*.py` в Docker.
10 KiB
Уборка сервиса генератора перед активными визитами
Дата: 2026-06-11
Статус: Draft
Связано: спека математической модели,
спека иерархической переработки,
generator/KNOWN_ISSUES.md,
задачи .scratch/feature-data-generator/issues/01..07.
Problem
После первых двух срезов новый генератор уже умеет строить связанный визит и
путь по страницам, но сервисный код начал распухать. В одном
generator/generator.py смешаны генеративная модель, чтение сида, тиковая
логика, Kafka, состояние, история пачек, метрики и запуск сервиса.
Следующая задача — активные визиты между тиками — добавит новый слой состояния.
Если продолжить в текущей форме, этот слой ляжет поверх временного
generate_tick_batch(), который набирает тик целыми визитами и не соответствует
целевой модели.
Goals
- Разнести код генератора по понятным учебным модулям без изменения внешнего поведения сервиса.
- Подготовить место для задачи 03: активные визиты должны появиться в отдельном
тиковом слое, а не внутри большого
generator.py. - Явно отделить временные части старой модели от контрактов, которые надо сохранить.
- Сохранить прежние команды запуска, Kafka-топики, формат сообщений и полезные метрики.
Non-goals
- Не реализовывать активные визиты из задачи 03.
- Не добавлять популяцию пользователей, возвраты, калибровку интенсивности или состояние версии 2.
- Не менять DDL, ETL, витрины или Superset.
- Не делать большой перепил поведения генератора под видом уборки.
Current state
generator/generator.py содержит около тысячи строк и несколько разных
ответственностей:
Config— настройки;EventDictionary— чтение и индексация JSONL-сида;EventGenerator— генерация визитов, страниц, пауз и интенсивности;BatchRecord,KafkaBatchHistory— история пачек в Kafka;GeneratorState,KafkaStateManager— состояние версии 1;KafkaPublisher,ensure_topics— работа с Kafka;GeneratorService— метрики, запуск, основной цикл.
generate_tick_batch() сейчас является переходным механизмом: он добирает
событийный бюджет полными визитами. Это допустимо после задач 01-02, но должно
быть заменено в задаче 03 тиковым слоем с активными визитами.
Options considered
- Минимальная уборка в одном файле. Быстро, но файл останется тяжёлым и следующая задача снова его раздует.
- Разнести код по модулям. Чище для чтения, лучше соответствует учебной цели и даёт место для активных визитов.
- Сначала выбросить лишнее. Может заметно сократить код, но требует решения, какие сервисные возможности больше не нужны.
Recommended approach
Принят смешанный вариант: разнести код по модулям и по ходу явно отметить или удалить очевидно временные части, если они не являются внешним контрактом.
Целевая форма:
generator/generator.py— тонкая точка входа и совместимый фасад для старых импортов тестов;generator/src/clickstream_generator/config.py— конфигурация и её валидация;generator/src/clickstream_generator/dictionary.py— загрузка и индексы исходных JSONL;generator/src/clickstream_generator/generation.py— чистая генеративная модель визита, страниц и пауз;generator/src/clickstream_generator/intensity.py— расчёт бюджета активности: Пуассон, часовой коэффициент, jitter;generator/src/clickstream_generator/runtime.py— переходный тиковый слой до активных визитов;generator/src/clickstream_generator/kafka_io.py— Kafka publisher, создание топиков, Kafka-state и история batch;generator/src/clickstream_generator/state.py— сериализуемое состояние генератора;generator/src/clickstream_generator/metrics.py— Prometheus-метрики;generator/src/clickstream_generator/service.py— основной сервисный цикл.
generator.py остаётся фасадом, потому что тесты и часть документации уже
используют импорт from generator import .... Рабочий пакет называется
clickstream_generator, чтобы не путать его с каталогом generator/ и файлом
generator.py. Dockerfile должен копировать src/ и выставлять
PYTHONPATH=/app/src.
Точное разбиение может быть чуть проще, если это уменьшит шум, но граница между моделью генерации, тиковым runtime и Kafka-интеграцией должна быть явной.
Decisions and rejected alternatives
- Принято: уборка идёт перед задачей 03. Причина: активные визиты добавляют новый слой состояния, и его нельзя удобно встроить в текущий монолит.
- Принято: внешнее поведение генератора не меняется. Цель задачи — форма кода, а не новая модель данных.
- Принято: исходники живут в
generator/src/clickstream_generator/, а не россыпью вgenerator/. Причина: так структура ближе к обычному Python-пакету и проще для учебного чтения. - Принято:
generate_tick_batch()считать временным переходным механизмом. После задачи 03 тик должен выпускать созревшие события активных визитов. - Отклонено: ограничиться перестановкой функций внутри
generator.py. Это не решает учебную читаемость и не создаёт ясного места для следующих срезов. - Отклонено: удалить историю пачек без отдельного решения. Её можно упростить или вынести, но пока не доказано, что она не нужна для демо и мониторинга.
Validation
- Все существующие тесты генератора проходят.
- Импорты, которые используют тесты, либо обновлены, либо сохранены через фасад
generator/generator.py. generate_batch()продолжает строить один связанный визит с монотонным временем, как после задач 01-02.- Временный
generate_tick_batch()не остаётся в чистой модели визита: он вынесен в переходный тиковый слой или явно подготовлен к замене задачей 03. - Сервисный контур продолжает публиковать в те же четыре Kafka-топика:
browser_events,location_events,device_events,geo_events. - Dockerfile и запуск контейнера учитывают новую структуру файлов.
- Рабочий пакет импортируется как
clickstream_generator, при этом старые импорты через фасадgenerator.pyпродолжают работать. - В коде есть ясное место, куда задача 03 добавит активные визиты без расширения Kafka-слоя и без переписывания генерации одного визита.
Documentation impact
- После реализации уборки обновить
generator/README.md: описать новую структуруsrc/clickstream_generatorи убрать формулировки, которые привязаны к одномуgenerator.py. - Если по ходу будет принято решение удалить или заменить
generator_batch_history, это должно быть отдельно отражено в README и в задаче реализации.