740fd2d7bd
repository map zavoz
8.2 KiB
8.2 KiB
4. Ключевые архитектурные решения
Базовые решения
| ID | Решение | Зачем | Последствия |
|---|---|---|---|
| ADR-01 | Модульный monolith на Django + Django Ninja | Быстрый delivery и единая транзакционная модель | Вертикальное масштабирование, не микросервисы |
| ADR-02 | Разделение на apps/* и api/v1/* |
Чёткие границы между domain и transport | Нужна дисциплина зависимостей |
| ADR-03 | Hash-based deterministic assignment в decide |
Выполнение B2-4 (стабильность результата) | Чувствительность к качеству subject_id |
| ADR-04 | Review policy: ApproverGroup + fallback ReviewSettings |
Выполнение требований по ревью и fallback | Политика плоская, без орг-иерархий |
| ADR-05 | Lifecycle как state machine + validators + DB constraint | Невалидные переходы и двойной запуск на флаг блокируются | Правила статусов централизованы |
| ADR-06 | Event ingestion с дедупом и PendingEvent |
Идемпотентность и out-of-order атрибуция | Дополнительная сложность обработки pending |
| ADR-07 | Guardrails как first-class модели + auto action | Авто-реакция на деградацию и аудит триггера | Риск ложных срабатываний при шумных данных |
| ADR-08 | Conflict domains (mutual_exclusion, priority) |
Детерминированное разрешение пересечений экспериментов | Дополнительные проверки на старте и в decide |
| ADR-09 | Базовая observability (health, ready, /metrics, JSON logs) |
Проверяемость B9 и эксплуатационная диагностика | SLA readiness подтверждается только live-demo |
| ADR-10 | Проверка качества через just и автотесты |
Воспроизводимая верификация B1/B8/B10 | - |
| ADR-11 | Кэш результата decide в cache backend (Redis/Valkey в целевом окружении) |
Снизить CPU/DB в hot-path | Ниже latency на повторяющихся запросах; риск stale-ответа в рамках TTL |
| ADR-12 | Режим записи Decision: sync|async|disabled; async через events.persist_decision; experiment_assigned всегда sync |
Снять write-pressure с hot-path без потери атрибуции | В async режиме нужна стабильность broker/worker и мониторинг очереди |
| ADR-13 | RBAC через роли admin/experimenter/approver/viewer + JWT bearer + endpoint guards |
Выполнение требований доступа и ревью-ответственности из раздела 0 ТЗ | Вся авторизация централизована в role guards; нужен контроль качества секретов JWT в окружении |
| ADR-14 | Типизированные feature flags (string/boolean/integer) и публичный контракт обновления только default_value |
Исключить несогласованные значения флагов и обеспечить безопасные переключения без релиза | Смена key/value_type решается созданием нового флага и миграцией использования |
| ADR-15 | Каталог типов событий (EventType) с required_fields, is_exposure, requires_exposure |
Явно отделить схему событий от runtime-обработки и обеспечить корректную атрибуцию | Требуется дисциплина ведения каталога; неактивные типы событий блокируют ingestion |
| ADR-16 | Каталог метрик (MetricDefinition) + явная привязка метрик к эксперименту (ExperimentMetric) |
Выполнение требований 5.4 ТЗ и единый расчёт для reports/guardrails | Изменение calculation_rule влияет на интерпретацию отчётов и требует управляемых изменений |
| ADR-17 | Завершение эксперимента через отдельную сущность ExperimentOutcome с обязательным rationale и валидируемыми outcome-сценариями |
Выполнение требований 2.6 и B6-4/B6-5 | Решение по rollout/rollback/no_effect становится аудитируемым и воспроизводимым |
| ADR-18 | Уведомления как rule-based pipeline: NotificationRule -> NotificationLog -> async flush, с dedup/rate-limit по event_key |
Закрыть FX notifications без “шторма” сообщений | Ограничение по каналам (telegram, smtp), требуется мониторинг failed delivery |
| ADR-19 | Поиск по эвристике среди Learnings | Реализовать поиск по базе | Поиск эвристический (веса/Jaccard), не ML и требует аккуратной интерпретации |
Неочевидные инварианты
- В один момент времени на один
FeatureFlagразрешён только один активный эксперимент (running|paused) через partialUniqueConstraint. - После старта эксперимента заморожены поля, влияющие на раздачу (
traffic_allocation,targeting_rules,flag), и запрещены изменения вариантов внеdraft. - Перед отправкой на review проверяются инварианты состава вариантов: минимум 2, ровно 1 control, сумма весов строго равна
traffic_allocation. - Один approver может оставить только одно одобрение по эксперименту (
unique_approval_per_user). - Для
requires_exposure=Trueсобытие без exposure не атрибутируется сразу: уходит вPendingEvent, промотируется после прихода exposure, затем очищается по TTL. - Одна метрика не может быть прикреплена к эксперименту дважды (
unique_experiment_metric). Learningхранится в one-to-one связи с экспериментом.
Ключевые риски
| Риск | Проявление | Смягчение | Остаток |
|---|---|---|---|
Stale ответ из кэша decide |
Кратковременный возврат устаревшего результата в пределах TTL | Revision-aware cache key + короткий TTL | Низкий/средний |
Потеря throughput при проблемах Celery в async |
Очередь растёт, запись Decision отстаёт |
Режимы `sync | async |
| Тяжёлые запросы отчётов на больших данных | Рост latency для percentile/агрегаций | DB aggregate + Subquery, фильтрация attributed событий, индексы |
Средний |
| Потеря отложенных атрибуций | PendingEvent истекает до прихода exposure |
TTL 7 дней + cleanup + промоция при exposure | Средний |
| Сбой каналов уведомлений | Отправка не доходит в Telegram/SMTP | NotificationLog со статусами и ошибками |
Средний |