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

143 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Уборка сервиса генератора перед активными визитами
Дата: 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/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 и в задаче реализации.