# Уборка сервиса генератора перед активными визитами Дата: 2026-06-11 Статус: Draft Связано: [спека математической модели](./2026-06-10-generator-math-model.md), [спека иерархической переработки](./2026-06-09-generator-rework-hierarchical.md), [`generator/KNOWN_ISSUES.md`](../../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/config.py` — конфигурация и её валидация; - `generator/dictionary.py` — загрузка и индексы исходных JSONL; - `generator/generation.py` — чистая генеративная модель визита, страниц и пауз; - `generator/intensity.py` — расчёт бюджета активности: Пуассон, часовой коэффициент, jitter; - `generator/kafka_io.py` — Kafka publisher, создание топиков, Kafka-state; - `generator/state.py` — сериализуемое состояние генератора; - `generator/service.py` — основной сервисный цикл и метрики; - `generator/generator.py` — тонкая точка входа или совместимый фасад для старых импортов тестов. Сейчас `generator/` не оформлен как Python-пакет: тесты импортируют `generator/generator.py` как модуль `generator`, а Dockerfile копирует только `generator.py`. В рамках этой уборки нужно сохранить совместимость импортов и обновить контейнерный запуск под новую структуру файлов; превращать каталог в пакет через `__init__.py` не требуется. Точное разбиение может быть чуть проще, если это уменьшит шум, но граница между моделью генерации, тиковым runtime и Kafka-интеграцией должна быть явной. ## Decisions and rejected alternatives - **Принято:** уборка идёт перед задачей 03. Причина: активные визиты добавляют новый слой состояния, и его нельзя удобно встроить в текущий монолит. - **Принято:** внешнее поведение генератора не меняется. Цель задачи — форма кода, а не новая модель данных. - **Принято:** `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 и запуск контейнера учитывают новую структуру файлов. - В коде есть ясное место, куда задача 03 добавит активные визиты без расширения Kafka-слоя и без переписывания генерации одного визита. ## Documentation impact - После реализации уборки обновить `generator/README.md`: описать новую структуру файлов и убрать формулировки, которые привязаны к одному `generator.py`. - Если по ходу будет принято решение удалить или заменить `generator_batch_history`, это должно быть отдельно отражено в README и в задаче реализации.