Files
voidea/docs/adr/004-rollout-process.md
T

6.9 KiB

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)

Критерии перехода:

  • Все тесты пройдены
  • Нет критических ошибок
  • Документация обновлена

Действия:

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 не фиксирует аномалий

Действия:

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 отслеживает

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
  • Решение человека

Процедура

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:

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()
);
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

Последствия

Положительные

  • Минимизация рисков
  • Быстрая реакция на проблемы
  • Эволюция с обратной связью
  • Прозрачность для команды

Отрицательные

  • Медленнее релиз
  • Сложнее управление
  • Требуется мониторинг

Конфигурация

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