Files
clickstream-ch-kafka-supers…/docs/specs/2026-06-11-generator-service-cleanup.md
T
Dmitry Dementiev 642789d484 refactor(generator): разнесён сервис генератора по src-пакету
- Зачем:
  - перед активными визитами нужно отделить генеративную модель от 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.
2026-06-11 15:00:50 +03:00

10 KiB
Raw Blame History

Уборка сервиса генератора перед активными визитами

Дата: 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

  • Минимальная уборка в одном файле. Быстро, но файл останется тяжёлым и следующая задача снова его раздует.
  • Разнести код по модулям. Чище для чтения, лучше соответствует учебной цели и даёт место для активных визитов.
  • Сначала выбросить лишнее. Может заметно сократить код, но требует решения, какие сервисные возможности больше не нужны.

Принят смешанный вариант: разнести код по модулям и по ходу явно отметить или удалить очевидно временные части, если они не являются внешним контрактом.

Целевая форма:

  • 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 и в задаче реализации.