Бэкапы: образцы настроек ведут алерты в тему «Metrics», неработавший сторож доступности удалён #3559

Merged
bot-backend merged 1 commit from fix/backup-notify-topic into main 2026-09-17 09:16:47 +00:00
Collaborator

#3164. Уведомления бэкапов уходят не в ту тему

Что было

В issue предположили, что TELEGRAM_TOPIC_ID не задан. Проверил на хостах 17.09 (только чтение): переменная задана, но в ней не та тема.

Хост Файл Значение
Beget /opt/gendesign/secrets/backup-notify.env (сторожа forgejo/couchdb и бэкап волта) TELEGRAM_TOPIC_ID=158
Beget /opt/gendesign/secrets/forgejo-backup.env (бэкап Forgejo) TELEGRAM_TOPIC_ID=158
Poincare /etc/default/gendesign-backup (backup.sh, backup-tradein-db.sh, сторожа, env-offbox) TELEGRAM_TOPIC_ID=158

158 — тема «алерты». По решению владельца в #3163 туда идут только клиентские инциденты. Инфраструктура, а значит и бэкапы, должна идти в 245 «Metrics».

Почему это не видно из репозитория

Тема задаётся только env-файлом на хосте. В образцах ops/gendesign-backup*.default.example её не было совсем. Поэтому следующий, кто заводит хост по образцу, отправит алерты в общую тему.

Есть и неочевидная ловушка. notify() читает BACKUP_ENV_FILE, только если в окружении нет токена или чата. Если положить тему в другой файл, она молча не подхватится.

Что сделано

  1. Образцы env. В gendesign-backup, -couchdb и -forgejo добавлена строка #TELEGRAM_TOPIC_ID=245. Рядом записаны причина (#3163) и ловушка «тема в одном файле с токеном и чатом». В образце forgejo блока Telegram не было вовсе, хотя на проде forgejo-backup.env держит канал именно там.
  2. ops/crontab-beget.cron сверен с живым crontab Beget. В живом у двух сторожей и у бэкапа волта стоит BACKUP_ENV_FILE=/opt/gendesign/secrets/backup-notify.env, в репозитории его не было. В /etc/default/gendesign-backup на Beget канала нет, так что переустановка crontab из репозитория молча заглушила бы алерты бэкапов. После правки строки без комментариев совпадают с crontab -l на обоих хостах: diff пустой для Beget и для Poincare.
  3. ops/uptime-healthcheck.sh и ops/gendesign-uptime.default.example удалены. Смежный вопрос issue: «не нужен или забыт при переезде». Замер 17.09:
    • Скрипт не запускается нигде. Его нет в crontab gendesign на Beget и на Poincare, нет в /etc/cron.d и в systemd-таймерах обоих хостов. Файла /etc/default/gendesign-uptime на Poincare тоже нет. #3119 фиксировал то же 27.08.
    • Его работу уже делает GlitchTip на Beget, отдельном от продукта хосте (uptime_monitor): https://gendsgn.ru/ и /health проверяются раз в 60 с, meraocenka.ru тоже раз в 60 с, плюс Forgejo, GlitchTip и CouchDB. Мониторы живые: последние смены состояния 11.09 (/health) и 12.09 (лэндинг Меры). Уведомления по ним создаются (alerts_notification, 17.09). Один из вебхуков идёт на metrics.gendsgn.ru, это 46.173.16.127, то есть Beget, и от Poincare он не зависит.
    • Декорация «сторож есть в репозитории» уже однажды ввела в заблуждение (#3119). Упоминания скрипта убраны из комментариев lib-backup.sh, check-backup-staleness.sh, selectel-bootstrap.sh, deploy.yml и из тестов test_2203_notify_topic.py / test_3059_alert_retry.py.
    • Сознательно не тронут tradein-mvp/docker-compose.selectel.yml: там два упоминания скрипта в комментариях. Правка под tradein-mvp/** запустила бы deploy-tradein ради комментария. Поправить при следующей содержательной правке этого файла.

Значение на хостах этот PR не меняет (158 → 245 нужно заменить руками, см. приёмку). Поэтому здесь нет Closes: issue закроется после правки хостов.

Тест

test_host_po_obraztsu_shlyot_bekapy_v_metriki[3 образца] в backend/tests/ops/test_2203_notify_topic.py. Тест запускает настоящий ops/check-backup-staleness.sh с отсутствующим маркером. В качестве BACKUP_ENV_FILE подаётся образец, заполненный по инструкции: строки TELEGRAM_* раскомментированы, подставлены токен и чат. Вместо curl стоит подставной скрипт, который записывает аргументы. Проверяется, что реально ушло бы в сеть: message_thread_id ровно [245].

До правки образцов тест красный на всех трёх образцах: у двух тема не передаётся, у forgejo curl не вызывается вовсе.

Прогоны

  • cd backend && uv run python -m pytest tests/ops -q -p no:cacheprovider128 passed, 4 failed, rc=1. Все 4 падения — известные test_2203_backup_trailer_grep_dashdash на macOS (BSD mktemp), до правки было 131 passed / те же 4 failed. Разница −3: убраны параметры удалённого скрипта (−3 в test_2203, −3 в test_3059) и добавлены 3 новых теста.
  • uv run python -m pytest tests/sql/test_auth_sql_migrations.py tests/test_2864_ruff_version_alignment.py -q → 9 passed, rc=0. Первый читает deploy.yml.
  • uv run ruff check → All checks passed, rc=0. uv run ruff format --check по двум изменённым тестам → rc=0.
  • bash -n для изменённых .sh и трёх образцов (они читаются через source) — ok. YAML deploy.yml парсится.

Фальсификация

В gendesign-backup.default.example тема заменена на 158, в gendesign-backup-forgejo.default.example строка темы удалена. Потом оба файла восстановлены из копий, diff -q чистый, снова 6 passed.

E       AssertionError: gendesign-backup.default.example: алерт бэкапа адресован ['message_thread_id=158'], а по #3163 инфраструктура идёт в «Metrics» (245)
E       AssertionError: gendesign-backup-forgejo.default.example: алерт бэкапа адресован в общую тему, а по #3163 инфраструктура идёт в «Metrics» (245)
FAILED tests/ops/test_2203_notify_topic.py::test_host_po_obraztsu_shlyot_bekapy_v_metriki[gendesign-backup.default.example]
FAILED tests/ops/test_2203_notify_topic.py::test_host_po_obraztsu_shlyot_bekapy_v_metriki[gendesign-backup-forgejo.default.example]
2 failed, 4 passed

Деплой

  • Запустится deploy.yml (ПТИЦА): пути ops/*.sh, ops/*.cron, backend/**, .forgejo/workflows/deploy.yml. Он пересоздаёт backend, worker и beat на Poincare. Перед мержем стоит проверить, нет ли долгих задач Celery в работе. Миграций нет.
  • deploy-tradein.yml не запустится: под tradein-mvp/** ничего не менялось. Гейт по scrape_runs не нужен.

Приёмка на проде (владелец или инженер с доступом к хостам, до 24.09.2026)

  1. Заменить TELEGRAM_TOPIC_ID=158 на 245 в трёх файлах из таблицы выше. Проверка: grep TELEGRAM_TOPIC_ID <файл>245.
  2. Проба адреса на каждом из трёх файлов. Проба отправляет сообщение в группу: set -a; . <файл>; set +a; curl -s https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHAT_ID -d message_thread_id=$TELEGRAM_TOPIC_ID -d text='проба темы бэкапов #3164' | python3 -c 'import json,sys; r=json.load(sys.stdin)["result"]; print(r.get("is_topic_message"), r.get("message_thread_id"))'. Ожидается True 245.
  3. После мержа и деплоя на Poincare: test ! -e /opt/gendesign/ops/uptime-healthcheck.sh && grep -c 'TELEGRAM_TOPIC_ID=245' /opt/gendesign/ops/gendesign-backup.default.example1.

🤖 Generated with Claude Code

## #3164. Уведомления бэкапов уходят не в ту тему ### Что было В issue предположили, что `TELEGRAM_TOPIC_ID` не задан. Проверил на хостах 17.09 (только чтение): переменная задана, но в ней не та тема. | Хост | Файл | Значение | |---|---|---| | Beget | `/opt/gendesign/secrets/backup-notify.env` (сторожа forgejo/couchdb и бэкап волта) | `TELEGRAM_TOPIC_ID=158` | | Beget | `/opt/gendesign/secrets/forgejo-backup.env` (бэкап Forgejo) | `TELEGRAM_TOPIC_ID=158` | | Poincare | `/etc/default/gendesign-backup` (backup.sh, backup-tradein-db.sh, сторожа, env-offbox) | `TELEGRAM_TOPIC_ID=158` | 158 — тема «алерты». По решению владельца в #3163 туда идут только клиентские инциденты. Инфраструктура, а значит и бэкапы, должна идти в 245 «Metrics». ### Почему это не видно из репозитория Тема задаётся только env-файлом на хосте. В образцах `ops/gendesign-backup*.default.example` её не было совсем. Поэтому следующий, кто заводит хост по образцу, отправит алерты в общую тему. Есть и неочевидная ловушка. `notify()` читает `BACKUP_ENV_FILE`, только если в окружении нет токена или чата. Если положить тему в другой файл, она молча не подхватится. ### Что сделано 1. **Образцы env.** В `gendesign-backup`, `-couchdb` и `-forgejo` добавлена строка `#TELEGRAM_TOPIC_ID=245`. Рядом записаны причина (#3163) и ловушка «тема в одном файле с токеном и чатом». В образце forgejo блока Telegram не было вовсе, хотя на проде `forgejo-backup.env` держит канал именно там. 2. **`ops/crontab-beget.cron` сверен с живым crontab Beget.** В живом у двух сторожей и у бэкапа волта стоит `BACKUP_ENV_FILE=/opt/gendesign/secrets/backup-notify.env`, в репозитории его не было. В `/etc/default/gendesign-backup` на Beget канала нет, так что переустановка crontab из репозитория молча заглушила бы алерты бэкапов. После правки строки без комментариев совпадают с `crontab -l` на обоих хостах: `diff` пустой для Beget и для Poincare. 3. **`ops/uptime-healthcheck.sh` и `ops/gendesign-uptime.default.example` удалены.** Смежный вопрос issue: «не нужен или забыт при переезде». Замер 17.09: - Скрипт не запускается нигде. Его нет в crontab `gendesign` на Beget и на Poincare, нет в `/etc/cron.d` и в systemd-таймерах обоих хостов. Файла `/etc/default/gendesign-uptime` на Poincare тоже нет. #3119 фиксировал то же 27.08. - Его работу уже делает GlitchTip на Beget, отдельном от продукта хосте (`uptime_monitor`): `https://gendsgn.ru/` и `/health` проверяются раз в 60 с, `meraocenka.ru` тоже раз в 60 с, плюс Forgejo, GlitchTip и CouchDB. Мониторы живые: последние смены состояния 11.09 (`/health`) и 12.09 (лэндинг Меры). Уведомления по ним создаются (`alerts_notification`, 17.09). Один из вебхуков идёт на `metrics.gendsgn.ru`, это 46.173.16.127, то есть Beget, и от Poincare он не зависит. - Декорация «сторож есть в репозитории» уже однажды ввела в заблуждение (#3119). Упоминания скрипта убраны из комментариев `lib-backup.sh`, `check-backup-staleness.sh`, `selectel-bootstrap.sh`, `deploy.yml` и из тестов `test_2203_notify_topic.py` / `test_3059_alert_retry.py`. - **Сознательно не тронут** `tradein-mvp/docker-compose.selectel.yml`: там два упоминания скрипта в комментариях. Правка под `tradein-mvp/**` запустила бы deploy-tradein ради комментария. Поправить при следующей содержательной правке этого файла. **Значение на хостах этот PR не меняет** (158 → 245 нужно заменить руками, см. приёмку). Поэтому здесь нет `Closes`: issue закроется после правки хостов. ### Тест `test_host_po_obraztsu_shlyot_bekapy_v_metriki[3 образца]` в `backend/tests/ops/test_2203_notify_topic.py`. Тест запускает настоящий `ops/check-backup-staleness.sh` с отсутствующим маркером. В качестве `BACKUP_ENV_FILE` подаётся образец, заполненный по инструкции: строки `TELEGRAM_*` раскомментированы, подставлены токен и чат. Вместо `curl` стоит подставной скрипт, который записывает аргументы. Проверяется, что реально ушло бы в сеть: `message_thread_id` ровно `[245]`. До правки образцов тест красный на всех трёх образцах: у двух тема не передаётся, у forgejo `curl` не вызывается вовсе. ### Прогоны - `cd backend && uv run python -m pytest tests/ops -q -p no:cacheprovider` → **128 passed, 4 failed**, rc=1. Все 4 падения — известные `test_2203_backup_trailer_grep_dashdash` на macOS (BSD mktemp), до правки было 131 passed / те же 4 failed. Разница −3: убраны параметры удалённого скрипта (−3 в test_2203, −3 в test_3059) и добавлены 3 новых теста. - `uv run python -m pytest tests/sql/test_auth_sql_migrations.py tests/test_2864_ruff_version_alignment.py -q` → 9 passed, rc=0. Первый читает `deploy.yml`. - `uv run ruff check` → All checks passed, rc=0. `uv run ruff format --check` по двум изменённым тестам → rc=0. - `bash -n` для изменённых `.sh` и трёх образцов (они читаются через `source`) — ok. YAML `deploy.yml` парсится. ### Фальсификация В `gendesign-backup.default.example` тема заменена на `158`, в `gendesign-backup-forgejo.default.example` строка темы удалена. Потом оба файла восстановлены из копий, `diff -q` чистый, снова 6 passed. ``` E AssertionError: gendesign-backup.default.example: алерт бэкапа адресован ['message_thread_id=158'], а по #3163 инфраструктура идёт в «Metrics» (245) E AssertionError: gendesign-backup-forgejo.default.example: алерт бэкапа адресован в общую тему, а по #3163 инфраструктура идёт в «Metrics» (245) FAILED tests/ops/test_2203_notify_topic.py::test_host_po_obraztsu_shlyot_bekapy_v_metriki[gendesign-backup.default.example] FAILED tests/ops/test_2203_notify_topic.py::test_host_po_obraztsu_shlyot_bekapy_v_metriki[gendesign-backup-forgejo.default.example] 2 failed, 4 passed ``` ### Деплой - Запустится `deploy.yml` (ПТИЦА): пути `ops/*.sh`, `ops/*.cron`, `backend/**`, `.forgejo/workflows/deploy.yml`. Он пересоздаёт backend, worker и beat на Poincare. Перед мержем стоит проверить, нет ли долгих задач Celery в работе. Миграций нет. - `deploy-tradein.yml` не запустится: под `tradein-mvp/**` ничего не менялось. Гейт по `scrape_runs` не нужен. ### Приёмка на проде (владелец или инженер с доступом к хостам, до 24.09.2026) 1. Заменить `TELEGRAM_TOPIC_ID=158` на `245` в трёх файлах из таблицы выше. Проверка: `grep TELEGRAM_TOPIC_ID <файл>` → `245`. 2. Проба адреса на каждом из трёх файлов. Проба отправляет сообщение в группу: `set -a; . <файл>; set +a; curl -s https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHAT_ID -d message_thread_id=$TELEGRAM_TOPIC_ID -d text='проба темы бэкапов #3164' | python3 -c 'import json,sys; r=json.load(sys.stdin)["result"]; print(r.get("is_topic_message"), r.get("message_thread_id"))'`. Ожидается `True 245`. 3. После мержа и деплоя на Poincare: `test ! -e /opt/gendesign/ops/uptime-healthcheck.sh && grep -c 'TELEGRAM_TOPIC_ID=245' /opt/gendesign/ops/gendesign-backup.default.example` → `1`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bot-backend added 1 commit 2026-09-17 07:51:22 +00:00
Бэкапы: образцы env ведут алерты в тему «Metrics», мёртвый uptime-сторож удалён (#3164)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 24s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 29s
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 3m15s
CI / backend-tests (pull_request) Successful in 7m37s
7218c2094c
Тема форума для уведомлений бэкапов задаётся только env-файлом на хосте, а в
образцах её не было вовсе. На проде она задана, но не та: 158 («алерты») в
/opt/gendesign/secrets/backup-notify.env и forgejo-backup.env на Beget и в
/etc/default/gendesign-backup на Poincare. По решению #3163 инфраструктура идёт
в 245 «Metrics». Значение на хостах этот коммит не меняет.

- ops/gendesign-backup*.default.example: строка #TELEGRAM_TOPIC_ID=245 с
  причиной и ловушкой: тема обязана лежать в одном файле с токеном и чатом,
  иначе notify() её не прочитает.
- ops/crontab-beget.cron сверен с живым crontab Beget: сторожа и бэкап волта
  получают BACKUP_ENV_FILE=/opt/gendesign/secrets/backup-notify.env. Без него
  переустановка crontab из репозитория глушила бы алерты бэкапов на Beget.
- ops/uptime-healthcheck.sh и его образец удалены: скрипт не запущен ни на
  одном хосте (crontab, cron.d, таймеры), доступность сторожат uptime-мониторы
  GlitchTip на Beget (gendsgn.ru, /health, meraocenka.ru — раз в 60 с).

Тест исполняет настоящий check-backup-staleness.sh с образцом, заполненным
по инструкции, и проверяет адрес в вызове curl: message_thread_id=245.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bot-backend merged commit af5eed19f9 into main 2026-09-17 09:16:47 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3559
No description provided.