feat(generator): добавлено модельное время live-потока

- Зачем:
  - генератор должен писать события от модельной точки T0 и проверяться повторяемо в ClickHouse.
- Что:
  - добавлены настройки модельного времени и передача модельной точки в live-тик.
  - дневной коэффициент считается по модельному времени и часовому поясу.
  - обновлены проверки, compose, документация и статус issue 02.
- Проверка:
  - make generator-test.
  - два чистых ClickHouse-прогона с GEN_STATE_RESET=true дали одинаковые контрольные числа.
This commit is contained in:
2026-06-14 17:23:12 +03:00
parent 31a71f93ea
commit efb07b0283
10 changed files with 248 additions and 18 deletions
@@ -3,13 +3,17 @@
import math
import random
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
from clickstream_generator.config import Config
def hour_factor(now: datetime | None = None) -> float:
def hour_factor(now: datetime | None = None, model_timezone: str = "UTC") -> float:
"""Возвращает коэффициент интенсивности в зависимости от часа дня."""
current = now or datetime.now(timezone.utc)
if current.tzinfo is None:
current = current.replace(tzinfo=timezone.utc)
current = current.astimezone(ZoneInfo(model_timezone))
hour = current.hour
if 9 <= hour <= 18:
return 1.2
@@ -18,9 +22,17 @@ def hour_factor(now: datetime | None = None) -> float:
return 1.0
def calculate_events_count(config: Config, rng: random.Random) -> int:
def calculate_events_count(
config: Config,
rng: random.Random,
now: datetime | None = None,
) -> int:
"""Вычисляет количество событий для текущего тика (Poisson + jitter)."""
lambda_minute = config.lambda_base_per_min * hour_factor()
if now is None:
factor = hour_factor()
else:
factor = hour_factor(now, config.model_timezone)
lambda_minute = config.lambda_base_per_min * factor
lambda_tick = lambda_minute * (config.tick_seconds / 60.0)
count = 0