После 24 спринтов regress-suite разросся; нестабильность блокирует доверие. Этот спринт: ловит flaky тесты, добавляет observability (Grafana + Prometheus alerts + RUNBOOK), сертифицирует 10× cert-прогон. 1. tests/regression/find-flaky.sh — 10× прогон + JSON-агрегатор → docs/flaky-tests.md (per-test pass/fail sequence + reproduce). 2. OrgFactory.signupWithRetry теперь honors Retry-After header (api-client.ts:ApiError.retryAfterSec). Stage rate-limit поднят: RATE_SIGNUP_HOUR=5000, RATE_PER_IP_MIN=5000 (~/food-market-stage/deploy/.env). 3. fullyParallel=true + workers=4 = тесты идут в недетерминированном порядке; isolation работает (OrgFactory per-test). 4. workers=4 даёт **2.4× ускорение** (66.6s → 27.7s). Worker-scoped фикстура lib/worker-org.ts добавлена как opt-in. 5. deploy/grafana/dashboards/quality-watchdog.json (10 панелей: smoke success ratio 7d, incidents, multi-tenant violations, current emoji, p95 by endpoint, step failures, RPS, DB p95, docs posted, disk free) + dashboards/README.md. quality-watchdog.sh пишет Prometheus textfile экспорт в ~/.fm-watchdog/textfile/quality_watchdog.prom для node_exporter. 6. deploy/prometheus/alerts.yml — 10 правил, 4 группы (uptime, errors, database, quality-watchdog). MultiTenantViolation = P0. deploy/prometheus/prometheus.yml — reference config. 7. docs/RUNBOOK.md +178 строк: action per alert (api-down, rps-drop, http-errors-spike/growing, doc-posting-errors, db-p95-high, disk-free-low, watchdog-red, multi-tenant-violation, watchdog-incident). Junior-friendly с конкретными командами. **Cert-прогон (10× workers=4):** 420/420 passed, 0 flaky, avg 30.1s/run, total 300.6s (< 5min budget). Изменения вне репо: - ~/food-market-stage/deploy/.env — RATE_* limits bumped. - ~/quality-watchdog.sh — добавлен .prom textfile экспорт. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
176 lines
8.2 KiB
YAML
176 lines
8.2 KiB
YAML
# 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"
|