294 lines
6.9 KiB
Markdown
294 lines
6.9 KiB
Markdown
# ADR-004: Постепенное развёртывание (Rollout)
|
|
|
|
**Статус:** принято
|
|
**Дата:** 2026-05-10
|
|
|
|
---
|
|
|
|
## Контекст
|
|
|
|
При выпуске нового функционала требуется минимизировать риски и быстро реагировать на проблемы.
|
|
|
|
Рассматривались:
|
|
- **Big bang** — сразу на всех пользователей
|
|
- **Feature flags** — включение для избранных
|
|
- **Постепенное развёртывание** — процент от пользователей
|
|
|
|
---
|
|
|
|
## Решение
|
|
|
|
**Поэтапное развёртывание с мониторингом**
|
|
|
|
```
|
|
Stage 0: Development → Тестирование агентами
|
|
Stage 1: 3 users → Первые пользователи
|
|
Stage 2: 1% → Расширение выборки
|
|
Stage 3: 5% → Продолжение
|
|
Stage 4: 15% → Почти все
|
|
Stage 5: 100% → Production
|
|
```
|
|
|
|
---
|
|
|
|
## Этапы
|
|
|
|
### Stage 0: Development
|
|
|
|
**Кто:** Агенты (QATesterAgent, FixAgent, UITestAgent)
|
|
|
|
**Критерии перехода:**
|
|
- Все тесты пройдены
|
|
- Нет критических ошибок
|
|
- Документация обновлена
|
|
|
|
**Действия:**
|
|
```python
|
|
async def promote_to_stage_1():
|
|
# 1. Финальная проверка тестов
|
|
test_results = await QATesterAgent.run_full_suite()
|
|
|
|
# 2. Проверка документации
|
|
await AuditAgent.verify_docs_complete()
|
|
|
|
# 3. Решение о переходе
|
|
if test_results.success:
|
|
RolloutAgent.set_stage(1)
|
|
notify_admins("Готов к rollout: 3 пользователя")
|
|
```
|
|
|
|
---
|
|
|
|
### Stage 1: 3 users
|
|
|
|
**Кто:** 3 добровольца (beta testers)
|
|
|
|
**Критерии перехода в Stage 2:**
|
|
- 2 дня без критических ошибок
|
|
- Error rate < 1%
|
|
- User feedback положительный
|
|
- ObserverAgent не фиксирует аномалий
|
|
|
|
**Действия:**
|
|
```python
|
|
async def check_stage_1_health():
|
|
metrics = await ObserverAgent.get_metrics(days=2)
|
|
|
|
# Проверки
|
|
if metrics.error_rate < 0.01:
|
|
if metrics.user_satisfaction > 0.8:
|
|
if not metrics.anomalies_detected:
|
|
await promote_to_stage_2()
|
|
else:
|
|
await analyze_anomalies()
|
|
else:
|
|
await log_issue("Low satisfaction")
|
|
```
|
|
|
|
---
|
|
|
|
### Stage 2: 1% пользователей
|
|
|
|
**Кто:** ~10 пользователей (при 1000 MAU)
|
|
|
|
**Критерии перехода в Stage 3:**
|
|
- 2 дня стабильности
|
|
- Нет regresion
|
|
- Performance acceptable (< 500ms)
|
|
|
|
---
|
|
|
|
### Stage 3: 5% пользователей
|
|
|
|
**Кто:** ~50 пользователей
|
|
|
|
**При проблемах:** Откат до Stage 2
|
|
|
|
---
|
|
|
|
### Stage 4: 15% пользователей
|
|
|
|
**Кто:** ~150 пользователей
|
|
|
|
**При проблемах:** Откат до Stage 3
|
|
|
|
---
|
|
|
|
### Stage 5: 100% (Production)
|
|
|
|
**Кто:** Все пользователи
|
|
|
|
**Критерии:**
|
|
- Все предыдущие stages стабильны
|
|
- Мониторинг непрерывный
|
|
- Подготовлен changelog для магазинов
|
|
|
|
---
|
|
|
|
## Мониторинг
|
|
|
|
### ObserverAgent отслеживает
|
|
|
|
```python
|
|
class RolloutMetrics:
|
|
error_rate: float # Цель: < 1%
|
|
response_time_p95: float # Цель: < 500ms
|
|
user_satisfaction: float # Цель: > 0.8
|
|
feature_usage: float # Цель: рост
|
|
complaints_count: int # Цель: 0
|
|
rollback_requests: int # Цель: 0
|
|
```
|
|
|
|
### При аномалиях
|
|
|
|
1. **Alert** → RolloutAgent получает уведомление
|
|
2. **Analysis** → FixAgent анализирует логи
|
|
3. **Decision** → Человек + агент решают
|
|
4. **Action** → Откат или продолжение
|
|
|
|
---
|
|
|
|
## Откат (Rollback)
|
|
|
|
### Когда
|
|
|
|
- Error rate > 5%
|
|
- Критические баги в production
|
|
- Решение человека
|
|
|
|
### Процедура
|
|
|
|
```python
|
|
async def rollback_to(stage: int):
|
|
# 1. Приостановить rollout
|
|
RolloutAgent.pause()
|
|
|
|
# 2. Зафиксировать состояние
|
|
await AuditAgent.log_rollback(stage)
|
|
|
|
# 3. Откатить код
|
|
await git.revert_to_stable_version()
|
|
|
|
# 4. Уведомить
|
|
notify_admins(f"Откат до Stage {stage}")
|
|
|
|
# 5. Создать задачу
|
|
await BacklogAgent.create_task(
|
|
title=f"Rollback reason: ...",
|
|
priority="high"
|
|
)
|
|
|
|
# 6. После исправления → вернуться к Stage 0
|
|
```
|
|
|
|
---
|
|
|
|
## UI в админ-панели
|
|
|
|
### Dashboard
|
|
|
|
```
|
|
Rollout Status: Stage 2 (1%)
|
|
|
|
Progress:
|
|
[████████░░░░░░░░░░░░░░░░░░░] 1%
|
|
|
|
Metrics:
|
|
- Error rate: 0.5% ✓
|
|
- Response time: 234ms ✓
|
|
- Users: 10/1000
|
|
|
|
Actions:
|
|
[Приостановить] [Откат] [Форсировать]
|
|
```
|
|
|
|
### История
|
|
|
|
```
|
|
Stage 0 → Stage 1: 2026-05-10 (PASSED)
|
|
Stage 1 → Stage 2: 2026-05-12 (PASSED)
|
|
Stage 2 → Stage 3: 2026-05-14 (IN PROGRESS)
|
|
```
|
|
|
|
---
|
|
|
|
## Feature Flags
|
|
|
|
Для гибкости используем Feature Flags:
|
|
|
|
```sql
|
|
CREATE TABLE feature_flags (
|
|
id UUID PRIMARY KEY,
|
|
name VARCHAR(100) UNIQUE NOT NULL,
|
|
enabled BOOLEAN DEFAULT FALSE,
|
|
rollout_percentage INT DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
```python
|
|
async def is_feature_enabled(user_id: UUID, feature: str) -> bool:
|
|
flag = await db.get_feature_flag(feature)
|
|
if not flag.enabled:
|
|
return False
|
|
|
|
# Проверка процента
|
|
user_hash = hash(user_id)
|
|
return (user_hash % 100) < flag.rollout_percentage
|
|
```
|
|
|
|
---
|
|
|
|
## Последствия
|
|
|
|
### Положительные
|
|
|
|
- Минимизация рисков
|
|
- Быстрая реакция на проблемы
|
|
- Эволюция с обратной связью
|
|
- Прозрачность для команды
|
|
|
|
### Отрицательные
|
|
|
|
- Медленнее релиз
|
|
- Сложнее управление
|
|
- Требуется мониторинг
|
|
|
|
---
|
|
|
|
## Конфигурация
|
|
|
|
```yaml
|
|
rollout:
|
|
stages:
|
|
- name: development
|
|
users: 0
|
|
duration: unlimited
|
|
- name: "3 users"
|
|
users: 3
|
|
duration: 2 days
|
|
- name: "1%"
|
|
users_percentage: 1
|
|
duration: 2 days
|
|
- name: "5%"
|
|
users_percentage: 5
|
|
duration: 2 days
|
|
- name: "15%"
|
|
users_percentage: 15
|
|
duration: 3 days
|
|
- name: "100%"
|
|
users_percentage: 100
|
|
duration: unlimited
|
|
```
|
|
|
|
---
|
|
|
|
## Ответственный
|
|
|
|
**Decision maker:** Owner + RolloutAgent
|
|
**Review date:** После каждого успешного rollout
|
|
|
|
---
|
|
|
|
*Создано: 2026-05-10*
|
|
*Управляется RolloutAgent* |