# Sprint 26: Prometheus alert rules для food-market. # # Загружается через prometheus.yml: # rule_files: # - alerts.yml # # Каждое правило → Alertmanager → Telegram/email. # Все runbook-ссылки указывают на docs/RUNBOOK.md в репо. # # Группировка: 4 группы по доменам — uptime / errors / database / quality-watchdog. groups: - name: food-market.uptime interval: 30s rules: - alert: ApiDown expr: up{job="food-market-api"} == 0 for: 1m labels: severity: critical runbook: api-down annotations: summary: "food-market API не отвечает на /metrics уже 1 минуту" description: | Prometheus не может scrap'нуть {{ $labels.instance }} > 1 минуты. Это означает либо процесс упал, либо порт недоступен. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#api-down" - alert: RpsDropped50Percent # RPS за 5 минут упал относительно среднего за час назад (5-минутка часовой давности). # Защита от ложных в пиках/спадах: только когда фактическая загрузка была заметной (>0.5 rps). expr: | sum(rate(http_requests_received_total[5m])) / clamp_min(sum(rate(http_requests_received_total[5m] offset 1h)), 0.001) < 0.5 and sum(rate(http_requests_received_total[5m] offset 1h)) > 0.5 for: 10m labels: severity: warning runbook: rps-drop annotations: summary: "RPS упал >50% относительно того же окна час назад" description: | Сейчас RPS = {{ $value | humanize }}, что меньше половины часовой давности. Возможно: упал процесс, нет трафика от клиентов, потерян DNS. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#rps-drop" - name: food-market.errors interval: 30s rules: - alert: HttpErrorsSpike # Доля 5xx-ответов > 10% от общего трафика за 5 минут. # 10% — порог, выше которого пользователи реально замечают. expr: | (sum(rate(http_requests_received_total{code=~"5.."}[5m])) / clamp_min(sum(rate(http_requests_received_total[5m])), 0.001)) > 0.10 for: 5m labels: severity: critical runbook: http-errors-spike annotations: summary: "Доля HTTP 5xx > 10% уже 5 минут" description: | Сейчас {{ $value | humanizePercentage }} от запросов возвращают 5xx. Скорее всего сломан какой-то контроллер или зависимость. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#http-errors-spike" - alert: HttpErrorRateGrowing # Темп роста 5xx-ошибок > 10%/min. expr: | deriv(sum(rate(http_requests_received_total{code=~"5.."}[5m]))[5m:1m]) > 0.10 / 60 for: 10m labels: severity: warning runbook: http-errors-growing annotations: summary: "Темп роста 5xx-ошибок > 10%/min на протяжении 10 минут" description: | Производная rate(5xx) положительная > 10%/min. Похоже на постепенную деградацию (не explosion). Проверь логи: что начало падать. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#http-errors-growing" - alert: DocumentPostingErrors expr: | sum(rate(food_market_documents_error_total[5m])) by (type) > 0.05 for: 5m labels: severity: warning runbook: doc-posting-errors annotations: summary: "Документы ({{ $labels.type }}) валятся чаще 1 раза в 20 секунд" description: | Тип={{ $labels.type }} даёт {{ $value }} ошибок/сек. Воркфлоу проведения ломается — посмотри logs или Hangfire-failed-jobs. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#doc-posting-errors" - name: food-market.database interval: 30s rules: - alert: DbQueryP95High # p95 DB-запросов > 500ms на протяжении 10 минут. expr: | histogram_quantile(0.95, sum(rate(food_market_db_query_duration_seconds_bucket[5m])) by (le)) > 0.5 for: 10m labels: severity: warning runbook: db-p95-high annotations: summary: "DB query p95 > 500ms 10 минут подряд" description: | p95 = {{ $value | humanizeDuration }}. Возможно: PG медленный, нет индекса, ANALYZE устарел, или массовый insert. См. runbook. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#db-p95-high" - alert: DiskFreeLow expr: food_market_disk_free_bytes < 5 * 1024 * 1024 * 1024 for: 5m labels: severity: critical runbook: disk-free-low annotations: summary: "Свободно < 5 ГБ на {{ $labels.mount }}" description: | Свободно: {{ $value | humanize1024 }}B. При достижении 0 БД встанет. Очисти логи / запусти VACUUM FULL / расширь том. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#disk-free-low" - name: food-market.quality-watchdog interval: 1m rules: - alert: WatchdogLastRunRed expr: quality_watchdog_last_run_status == 0 for: 5m labels: severity: warning runbook: watchdog-red annotations: summary: "quality-watchdog последний прогон красный (>5 мин)" description: | Хотя бы один из 8 шагов упал. Посмотри docs/quality-status.md или ~/.fm-watchdog/quality.log. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#watchdog-red" - alert: MultiTenantViolation # Multi-tenant leak — самый дорогой баг, alert немедленный. expr: increase(quality_watchdog_step_failure_total{step="multi_tenant"}[1h]) > 0 for: 1m labels: severity: critical runbook: multi-tenant-violation annotations: summary: "🚨 Multi-tenant LEAK обнаружен watchdog'ом" description: | Шаг multi_tenant failed в последнем прогоне. Org B видит данные A. ЭТО P0. Немедленно разверни stage в read-only mode и проверь tenant-filter. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#multi-tenant-violation" - alert: WatchdogIncidentCreated expr: increase(quality_watchdog_incidents_total[1h]) > 0 for: 1m labels: severity: warning runbook: watchdog-incident annotations: summary: "Watchdog создал incident — 2+ подряд красных прогона" description: | Один и тот же шаг упал 2 раза подряд. Server-Claude получит incident-файл в очередь. Проверь ~/.fm-watchdog/incident-*.txt. runbook_url: "https://forgejo.local/nns/food-market/src/branch/main/docs/RUNBOOK.md#watchdog-incident"