fix(ops): алерт не теряется от одного сетевого отказа — ретрай в обеих notify() (#3059) #3095
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3095
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/3059-alert-retry"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что не так
Путь Selectel→Telegram теряет соединения. Замер 26.08 с Poincare, 40 подключений к закреплённому (#3093)
149.154.167.220:Отказы происходят на стадии подключения — быстрые стабильные успехи на фоне редких таймаутов, а не деградация под нагрузкой. Три остальных дата-центра Telegram с Selectel недостижимы вовсе (таймаут 8 с), поэтому закрепление адреса из #3093 потери убрать не может: запасного адреса просто нет.
Бот это переживает своими ретраями — 106 таймаутов
getUpdatesза сутки, из них 97 лечатся первой же повторной попыткой. Алерты — нет:ops/uptime-healthcheck.sh:61curl, дальше|| log WARNops/lib-backup.sh:48curl→ сразу почта (#3070)Сторож, который не может дозваться, — худший вид самоскрывающейся поломки: чем хуже дела на проде, тем выше шанс, что о них не сообщат. Отдельная ирония — ниже в том же
uptime-healthcheck.shHTTP-проверки уже повторяются цикломfor attempt in $(seq 1 ...): ретраили то, что измеряют, но не то, чем докладывают.Что стало
Цикл из трёх попыток в обеих
notify().Почему цикл, а не
curl --retry: семантика--max-timeпри ретраях зависит от версии curl, а цикл гарантирует таймаут на КАЖДУЮ попытку и повторяет идиому, уже принятую в этом файле.Дубль вместо потери — осознанный размен.
sendMessageне идемпотентен, но замер показал, что отказ случается ДО отправки запроса, так что повтор почти никогда не продублирует доставленное. Лишний алерт безвреден, пропущенный — нет.Верхняя граница не менее важна нижней: ровно три попытки, hourly-крон не зависает на недоступном Telegram. Задержка между попытками —
NOTIFY_RETRY_DELAY(по умолчанию 2 с), чтобы тесты не спали.Тесты
backend/tests/ops/test_3059_alert_retry.py, 7 штук. Исполняют РЕАЛЬНЫЕnotify(), извлечённые из обоих скриптов (не копию, не пересказ), с подставнымcurl, который отказывает заданное число раз кодом 28 (operation timeout— ровно то, что наблюдалось), и считают ФАКТИЧЕСКОЕ число вызовов:curlпозван 2 раза (оба скрипта);Фальсификация: на исходных скриптах краснеют 6 из 7. Проходит только
test_backup_falls_back_to_mail_when_telegram_is_really_down— он фиксирует сохранённое поведение, а не регресс, и это честно отмечено в его докстринге.Проверено помимо тестов
bash -nобоих скриптов — та же проверка, что в CI (ci.yml:125: shellcheck там нет намеренно);[[ ... ]] && cmdв конце тела цикла безопасна подset -euo pipefail(стоит вuptime-healthcheck.sh:25) — проверено исполнением, а не рассуждением о POSIX;tests/opsцеликом — 22 passed;deploy.ymlматчитops/*.shглобом (#2203) и делаетgit reset --hard.Что этот PR НЕ чинит
Сами потери. Это свойство сетевого пути Selectel↔Telegram, кодом не лечится — варианты (прокси-пул / бот на Beget / запрос в поддержку) остаются в #3059 за владельцем. Здесь только то, что алерт переживает единичный отказ.
Отдельная находка — сторож, похоже, нигде не запущен
Проверил оба VPS: файл
/opt/gendesign/ops/uptime-healthcheck.shна месте, но ни cron, ни systemd-таймера, ни лога/var/log/gendesign-uptime.log— ни на Beget, ни на Poincare, ни подroot, ни подgendesign.Утверждать «не работает нигде» не могу: по замыслу (
#75 B6-1, шапка скрипта) он и должен крутиться на ВНЕШНЕЙ машине — ноутбуке, free-tier боксе или cron'е shared-хостинга Beget, куда у меня доступа нет. Но если он всё же живёт на внешнем хосте, туда эта правка сама не доедет:ops/*.shкопируется только на прод-VM. Стоит проверить и обновить копию вручную.Refs #3059, #3093