# Генератор событий (MVP rev5) > Перед использованием как источник витрин прочитать > [KNOWN_ISSUES.md](./KNOWN_ISSUES.md): часть старого дефекта уже исправлена > (один `click_id` на визит, путь по страницам, монотонное время), но популяция > возвращающихся пользователей и полноценное состояние активных визитов ещё > остаются следующими шагами. Автономный генератор событий для Kafka с режимом `steady-stream`. ## Архитектура ``` generator-service -> Kafka topics -> (потребители отдельно) ``` Генератор работает автономно и не зависит от потребителей (Airflow, ClickHouse). ## Режим работы: `steady-stream` - Публикуем постепенно, **короткими тиками** (по умолчанию каждые 5 секунд) - На каждом тике отправляем небольшую порцию сообщений - Держим целевую интенсивность `events/min` без крупных минутных batch: тик набирается из одного или нескольких визитов до рассчитанного бюджета событий - Распределяем события по 4 топикам: - `browser_events` - `location_events` - `device_events` - `geo_events` - Публичный вызов генеративного ядра строит один визит: общий `click_id`, разные `event_id`, общий device/geo-контекст, путь по страницам воронки и строго растущие запланированные `event_timestamp`. - Сохраняем связи `event_id <-> location`, `click_id <-> device/geo`. ## Конфигурация (env) | Переменная | Описание | По умолчанию | |------------|----------|--------------| | `KAFKA_BOOTSTRAP_SERVERS` | Адрес Kafka | `kafka:29092` | | `GEN_TICK_SECONDS` | Интервал между тиками | `5` (1-10 сек рекомендуется) | | `GEN_LAMBDA_BASE_PER_MIN` | Базовая интенсивность (событий/мин) | `200` | | `GEN_JITTER_PCT` | Процент вариативности | `20` | | `GEN_MIN_EVENTS_PER_TICK` | Минимум событий за тик | `5` | | `GEN_MAX_EVENTS_PER_TICK` | Максимум событий за тик | `50` | | `GEN_MAX_SESSION_EVENTS` | Потолок длины одного визита, защита от петель | `30` | | `GEN_DATA_DIR` | Путь к JSONL файлам | `/data` | | `GEN_SEED` | Сид для воспроизводимости | — | | `GEN_ENABLED` | Включить генерацию | `true` | | `GEN_METRICS_PORT` | Порт для Prometheus | `9109` | | `GEN_STATE_ENABLED` | Сохранять состояние между рестартами | `true` | | `GEN_STATE_RESET` | Сбросить состояние при старте | `false` | ### Режим "раз в минуту" (для демо) Для контролируемых демо можно установить: ```bash GEN_TICK_SECONDS=60 GEN_MIN_EVENTS_PER_TICK=50 GEN_MAX_EVENTS_PER_TICK=500 ``` ## Управление через Makefile ```bash # Запустить только генератор make generator-up # Остановить генератор make generator-down # Смотреть логи make generator-logs # Перезапуск с пересборкой make generator-restart # Запуск тестов make generator-test ``` ## Метрики Prometheus Генератор экспортирует метрики на `:9109/metrics`: | Метрика | Тип | Описание | |---------|-----|----------| | `generator_events_total` | Counter | Всего отправлено событий (по топикам) | | `generator_publish_errors_total` | Counter | Ошибки публикации (по топикам) | | `generator_tick_duration_seconds` | Histogram | Длительность тика | | `generator_last_success_timestamp` | Gauge | Время последнего успешного тика | ### Проверка метрик ```bash curl http://localhost:9109/metrics curl http://localhost:9090/api/v1/targets | grep generator ``` ## Мониторинг в Grafana **Dashboard URL:** `http://localhost:3000/d/generator-overview` Дашборд "Generator Overview" предоставляет полную визуализацию работы генератора: ### Ключевые панели | Панель | Метрика | Описание | |--------|---------|----------| | **Events/min** | `rate(generator_events_total[1m]) * 60` | Текущая скорость генерации | | **Tick Duration** | `generator_tick_duration_seconds` | p50 и p99 длительности тика | | **Last Successful Tick** | `generator_last_success_timestamp` | Время последнего успешного тика | | **Events per Hour** | `increase(generator_events_total[1h])` | 24-часовое распределение по топикам (bar chart) | | **Errors** | `generator_publish_errors_total` | Общее число и rate ошибок | | **Generator Status** | derived | Активен ли генератор | ### Структура дашборда Дашборд разделён на 6 секций: 1. **Overview** — ключевые метрики (events/min, tick duration, last success) 2. **Events by Topic** — bar chart Events per Hour, rate by topic, total counters 3. **Errors** — total errors, error rate, errors by topic 4. **Tick Statistics** — duration distribution (p50/p95/p99), events per tick, hour factor 5. **Status** — generator status, generator health (heartbeat), time since last tick 6. **Info** — полезные команды и параметры конфигурации ### Доступ к дашборду Дашборд автоматически загружается в Grafana при старте контейнера (provisioning). ```bash # Открыть дашборд open http://localhost:3000/d/generator-overview # Перезагрузить provisioning (если дашборд не появился) curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/dashboards/reload ``` ## История batch История пишется в Kafka-топик `generator_batch_history` (JSON). **Контракт топика:** - Название фиксировано: `generator_batch_history` (не конфигурируется) - Формат: JSON с ключом `batch_id` **Важно:** генератор требует работающей Kafka. Без Kafka генератор упадёт при старте или потеряет события. Для мониторинга доступности используйте Prometheus-метрики (`generator_last_success_timestamp`). Поля сообщения: - `batch_id` — идентификатор батча - `started_at` / `finished_at` — время начала/окончания (ISO format) - `sent_total` — всего отправлено - `sent_browser/location/device/geo` — по топикам - `status` — success/partial/error - `error_message` — описание ошибки (если есть) ### Чтение истории из Kafka ```bash docker compose exec kafka /opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server kafka:29092 \ --topic generator_batch_history \ --from-beginning ``` ## State Recovery (восстановление состояния) Генератор сохраняет своё состояние между перезапусками в Kafka-топик `generator_state` (compact topic). Это позволяет: - Продолжить нумерацию тиков с места остановки (continuity) - Сохранить последовательность случайных чисел (RNG state) - Восстановить интенсивность генерации после рестарта **Важно:** восстанавливается continuity по номеру тика и интенсивности, но не гарантируется отсутствие дублирования событий — `event_id` и `click_id` всегда генерируются заново (`uuid4()`). ### Как работает 1. После каждого успешного тика состояние сохраняется в `generator_state` 2. При старте генератор читает последнее состояние из топика 3. Если состояние найдено - продолжает с сохранённого tick 4. Если нет - начинает с tick=1 ### Топик `generator_state` - **Название**: фиксировано `generator_state` - **Тип**: compact topic (хранится только последнее значение для каждого ключа) - **Ключ**: `default` (для возможности нескольких генераторов в будущем) - **Конфигурация**: `cleanup.policy=compact`, минимальный retention ### Просмотр текущего состояния ```bash docker compose exec kafka /opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server kafka:29092 \ --topic generator_state \ --from-beginning \ --property print.key=true ``` ### Сброс состояния (начать сначала) ```bash # Вариант 1: через env (рекомендуется) GEN_STATE_RESET=true docker compose up -d generator # Вариант 2: удалить топик полностью docker compose exec kafka /opt/kafka/bin/kafka-topics.sh \ --bootstrap-server kafka:29092 \ --delete \ --topic generator_state ``` ### Отключение сохранения состояния ```bash GEN_STATE_ENABLED=false docker compose up -d generator ``` При отключенном state management генератор всегда начинает с tick=1, RNG инициализируется с GEN_SEED (или случайно). ## Тестирование Тесты написаны на **pytest**. ### Запуск тестов ```bash # Через Makefile (рекомендуется) make generator-test # Вручную через Docker docker build -t generator:test . docker run --rm -v $(PWD):/workspace -w /workspace/generator generator:test pytest tests/ -v # Конкретный файл тестов docker run --rm -v $(PWD):/workspace -w /workspace/generator generator:test pytest tests/test_generation.py -v ``` ### Структура тестов ``` generator/tests/ ├── conftest.py # Fixtures pytest ├── test_config.py # Тесты конфигурации ├── test_generation.py # Тесты генерации событий ├── test_history.py # Тесты структуры BatchRecord ├── test_kafka_history.py # Тесты KafkaBatchHistory ├── test_service.py # Тесты GeneratorService └── test_state.py # Тесты GeneratorState и KafkaStateManager ``` ### Интеграционный тест ```bash # Запустить стек с генератором make generator-up # Проверить логи make generator-logs # Проверить метрики curl http://localhost:9109/metrics # Проверить сообщения в Kafka docker compose exec kafka /opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server kafka:29092 --topic browser_events --from-beginning ```