gendesign/ops
bot-backend c7df2732bd
All checks were successful
CI / changes (pull_request) Successful in 10s
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m48s
CI / backend-tests (pull_request) Successful in 22m26s
fix(ops): алерт не теряется от одного сетевого отказа (#3059)
Путь Selectel-Telegram теряет соединения. Замер 26.08 с Poincare, 40
подключений к закреплённому (#3093) 149.154.167.220:

    успешно 37 из 40, отказов 3 (7.5%) - все TimeoutError
    время успешных: min 0.14s, медиана 0.15s, max 0.17s

Отказы происходят на стадии ПОДКЛЮЧЕНИЯ - быстрые стабильные успехи на фоне
редких таймаутов. Три остальных дата-центра Telegram с Selectel недостижимы
вовсе, так что закрепление адреса потери убрать не может: запасного адреса
нет. Бот это переживает своими ретраями (106 таймаутов за сутки, 97 лечатся
первой же повторной попыткой), а вот алерты - нет.

uptime-healthcheck.sh: был один curl и `|| log WARN` - каждый отказ терял
уведомление целиком. Сторож, который не может дозваться, - худший вид
самоскрывающейся поломки: чем хуже дела на проде, тем выше шанс, что о них
не сообщат. Ирония в том, что ниже в этом же файле HTTP-проверки уже
повторяются циклом: ретраили то, что измеряют, но не то, чем докладывают.

lib-backup.sh: тоже один curl, но с падением в почту (#3070). Алерт не
терялся, зато каждый транзиентный таймаут впустую сжигал последнее средство
вместо простого переподключения.

Стало: цикл из трёх попыток в обеих notify(). Не `curl --retry` - семантика
--max-time при ретраях зависит от версии curl, а цикл даёт таймаут на КАЖДУЮ
попытку и повторяет идиому, уже принятую в uptime-healthcheck.sh.

Дубль вместо потери - осознанный размен: sendMessage не идемпотентен, но
отказ случается ДО отправки запроса, так что повтор почти никогда не
продублирует доставленное. Лишний алерт безвреден, пропущенный - нет.

Тесты (backend/tests/ops/test_3059_alert_retry.py, 7 шт) исполняют РЕАЛЬНЫЕ
notify(), извлечённые из обоих скриптов, с подставным curl, отказывающим
заданное число раз, и считают фактическое число попыток.

Фальсификация: на исходных скриптах краснеют 6 из 7. Проходит только
test_backup_falls_back_to_mail_when_telegram_is_really_down - он фиксирует
сохранённое поведение, а не регресс.

Проверено: `bash -n` обоих скриптов (та же проверка, что в CI - shellcheck
там нет); конструкция `[[ ]] && cmd` в конце тела цикла безопасна под
`set -euo pipefail`, который стоит в uptime-healthcheck.sh:25 (проверено
исполнением, не рассуждением); tests/ops целиком - 22 passed.
2026-08-26 10:02:46 +03:00
..
db-bootstrap feat(ops): лёгкий Postgres на Beget под forgejo и glitchtip (#3080) 2026-08-24 16:31:12 +00:00
glitchtip-auth-forwarder fix(tradein/observability): stop basic_auth 401 and RetryError GlitchTip noise 2026-08-15 18:08:04 +03:00
backup-couchdb.sh chore(ops): backup-couchdb.sh исполняемый, как остальные бэкапы (#3091) 2026-08-25 05:48:41 +00:00
backup-forgejo.sh feat(ops): лёгкий Postgres на Beget под forgejo и glitchtip (#3080) 2026-08-24 16:31:12 +00:00
backup.sh fix(ops): бэкап без выгрузки в S3 падает, а не рапортует успех (#3086) 2026-08-24 17:50:18 +00:00
check-backup-staleness.sh fix(ops): restore +x on new ops/*.sh (exec bit lost in prior commit, Windows core.filemode=false) 2026-08-21 15:38:31 +03:00
crontab-beget.cron feat(ops): у волта Obsidian появился автоматический бэкап (#3090) 2026-08-25 05:44:16 +00:00
crontab-poincare.cron fix(ops): бэкап без выгрузки в S3 падает, а не рапортует успех (#3086) 2026-08-24 17:50:18 +00:00
docker-prune.sh chore(ops): снятие зависших job-контейнеров раннера + лимит journald + мёртвый Caddy-блок 2026-08-15 22:27:48 +03:00
gendesign-backup-couchdb.default.example feat(ops): у волта Obsidian появился автоматический бэкап (#3090) 2026-08-25 05:44:16 +00:00
gendesign-backup-forgejo.default.example feat(ops): лёгкий Postgres на Beget под forgejo и glitchtip (#3080) 2026-08-24 16:31:12 +00:00
gendesign-backup.default.example fix(ops): бэкап без выгрузки в S3 падает, а не рапортует успех (#3086) 2026-08-24 17:50:18 +00:00
gendesign-uptime.default.example ci(infra): coverage-gate (#68) + OpenAPI codegen-assert (#69) + uptime monitoring (#75) 2026-06-13 23:28:06 +05:00
journald-gendesign.conf.example chore(ops): снятие зависших job-контейнеров раннера + лимит journald + мёртвый Caddy-блок 2026-08-15 22:27:48 +03:00
lib-backup.sh fix(ops): алерт не теряется от одного сетевого отказа (#3059) 2026-08-26 10:02:46 +03:00
restore-drill.sh fix(ops): бэкап без выгрузки в S3 падает, а не рапортует успех (#3086) 2026-08-24 17:50:18 +00:00
restore.sh fix(ops): восстановление не падает в хвосте из-за незаведённых ролей (#3089) 2026-08-25 05:18:53 +00:00
selectel-audit.sh feat(ci): деплой проверяет, к тому ли хосту подключился (#3079) 2026-08-24 16:36:50 +00:00
selectel-bootstrap.sh fix(ops): закрепить рабочий адрес api.telegram.org на новом хосте 2026-08-23 23:32:35 +03:00
selectel-ci-access.sh feat(ci): деплой проверяет, к тому ли хосту подключился (#3079) 2026-08-24 16:36:50 +00:00
split-infra-postgres.sh fix(ops): страж повторной заливки перестал молча пропускаться (#3092) 2026-08-25 06:44:41 +00:00
uptime-healthcheck.sh fix(ops): алерт не теряется от одного сетевого отказа (#3059) 2026-08-26 10:02:46 +03:00