34 lines
2.2 KiB
Markdown
34 lines
2.2 KiB
Markdown
# 5. Критичный путь
|
||
|
||
## Decide (`apps/decision/services.py`)
|
||
|
||
1. `flag` из cache/DB; при `FeatureFlag.default_value` update удаляется `flag:{key}`.
|
||
2. `active_experiment` из cache/DB.
|
||
3. Формируется cache key результата (`flag`, `subject`, digest атрибутов, ревизии `flag/experiment`).
|
||
4. При cache hit возвращается тот же outcome/reason/value с новым `decision_id`.
|
||
5. При cache miss выполняются проверки: running experiment, targeting, participation limits, domain conflicts, traffic allocation.
|
||
6. Если назначен вариант, выбирается детерминированно по hash + weights.
|
||
7. Результат может быть закэширован (по whitelist reason).
|
||
8. Запись `Decision` зависит от `DECISION_WRITE_MODE`: `sync|async|disabled`; для `experiment_assigned` запись всегда sync.
|
||
|
||
Reason-коды: `flag_not_found`, `no_active_experiment`, `targeting_mismatch`, `participation_limit`, `domain_conflict`, `outside_traffic_allocation`, `no_variants`, `experiment_assigned`.
|
||
|
||
## Events (`apps/events/services.py`)
|
||
|
||
1. Валидация типа события и payload.
|
||
2. Дедуп по `event_id`.
|
||
3. Exposure: `Exposure` + `Event`, затем промоция `PendingEvent`.
|
||
4. Conversion: при `requires_exposure=True` без exposure -> `PendingEvent` (TTL 7 дней), иначе attributed `Event`.
|
||
|
||
## Reports (`apps/reports/services.py`)
|
||
|
||
- По каждому варианту: `exposures`, `unique_subjects`, значения выбранных метрик.
|
||
- Поддерживается период `start/end`.
|
||
- `average` считает DB `Avg`, `percentile` - DB aggregate (`PERCENTILE_CONT` в PostgreSQL).
|
||
- Связь событий с экспозициями строится через `Subquery`, без materialization списка `decision_ids` в Python.
|
||
|
||
## Guardrails (`apps/guardrails/services.py`)
|
||
|
||
- Celery проверяет running эксперименты.
|
||
- При breach: `GuardrailTrigger` + действие (`pause`/`rollback`) + `ExperimentLog` + enqueue уведомления.
|