chore(ops): развести crontab по хостам под переезд
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 2m1s
CI / backend-tests (pull_request) Successful in 17m15s

Сегодняшний crontab Beget'а обслуживает ОБА контура сразу — и остающийся
(Forgejo), и уезжающий (tradein/gendesign). После 30.08 это перестанет
быть верным, а сам crontab об этом не узнает.

Пять записей начнут ходить в контейнеры, которых на Beget больше нет:

  0  5 * * *  backfill_houses_dadata      docker exec tradein-backend
  30 5 * * *  geocode_deals_from_houses   docker exec tradein-backend
  45 5 * * *  geocode_deals_nominatim     docker exec tradein-backend
  30 4 * * *  backup-tradein-db.sh        dump из tradein-postgres
  30 3 * * *  ops/backup.sh               dump из gendesign-postgres

Падающие по ночам задачи — ещё полбеды. Хуже, что вместе с ними перестанут
обновляться sentinel'ы бэкапов; сторож честно это заметит и упрётся в то,
что канал оповещения не настроен (#2203: TELEGRAM_* нет ни в одном
env-файле). То есть бэкапы обоих продуктовых кластеров пропадут МОЛЧА.

Зеркальный и более опасный случай: если на Poincare crontab не установить
вовсе, там не будет НИ ОДНОГО бэкапа — и узнать об этом неоткуда, потому
что сторож пропущенных прогонов живёт в том же crontab'е. Отсутствие
бэкапов обнаружилось бы в момент, когда они понадобятся.

Поэтому два эталонных файла, а не инструкция в раннбуке: переход должен
быть явным действием (`crontab ops/crontab-<хост>.cron`), а не «забыли
поправить».

Разбор по хостам:
  Beget    — backup-forgejo.sh + его сторож + docker-prune (здесь остаются
             CI-раннеры, их тома и растут)
  Poincare — оба продуктовых бэкапа + два их сторожа + три задачи
             обогащения/геокодирования + СВОЙ docker-prune

docker-prune нужен на обоих: на Beget он чистит тома раннеров, на Poincare
образы продуктового стека. Это не «переехавшая» запись, а две разные.

Заодно логи переведены с /tmp на /opt/gendesign/logs: половина записей
писала в /tmp, который чистится при перезагрузке — именно поэтому историю
отказов бэкапов раньше не удавалось восстановить.

Времена оставлены прежние: чтобы при разборе後 переезда не гадать, что
изменилось — поведение или расписание.

`ops/*.cron` добавлен в paths deploy.yml: файлы не исполняются деплоем, но
должны физически лежать в /opt/gendesign, иначе в окне их нечем будет
установить (тот же класс, что #2887).

Проверено: 11 расписаний разобраны построчно — 5 полей + команда, ошибок 0;
deploy.yml остаётся валидным YAML.

Refs #3059, #3057, #2203
This commit is contained in:
bot-backend 2026-08-24 04:46:18 +03:00
parent 01128e6331
commit e576f8c256
3 changed files with 97 additions and 0 deletions

View file

@ -39,6 +39,10 @@ on:
# снова забыли бы (см. как этот самый комментарий выше был точечным про
# docker-prune.sh и не спас backup.sh). Глоб закрывает класс целиком.
- "ops/*.sh"
# Эталонные crontab'ы двух хостов (#3059). Деплоем не исполняются, но
# должны физически лежать в /opt/gendesign — иначе их нечем будет
# установить в окне: `crontab /opt/gendesign/ops/crontab-<хост>.cron`.
- "ops/*.cron"
workflow_dispatch:
# #2950: ОБЩАЯ группа с deploy-tradein.yml — не опечатка и не копипаста.

45
ops/crontab-beget.cron Normal file
View file

@ -0,0 +1,45 @@
# crontab ОСТАЮЩЕГОСЯ хоста (Beget, 46.173.16.127) — после переезда 30.08.
#
# Устанавливать НЕ РАНЬШЕ, чем стек уедет на Selectel:
# crontab /opt/gendesign/ops/crontab-beget.cron
# crontab -l # сверить
#
# ЗАЧЕМ ЭТОТ ФАЙЛ. Сегодняшний crontab Beget'а обслуживает ОБА контура сразу:
# и остающийся (Forgejo), и уезжающий (tradein/gendesign). После переезда пять
# записей начнут ходить в контейнеры, которых на этом хосте больше нет —
# `docker exec tradein-backend ...` будет падать каждую ночь. Само по себе это
# ещё полбеды; беда в том, что вместе с ними перестанут обновляться sentinel'ы
# бэкапов, сторож это честно заметит — и упрётся в то, что канал оповещения
# не настроен (#2203: TELEGRAM_* нет ни в одном env-файле). То есть бэкапы
# пропадут молча.
#
# Разделение на два файла — чтобы этот переход был явным действием, а не
# «забыли поправить crontab».
# ── Forgejo: остаётся здесь ─────────────────────────────────────────────────
# Конфиг лежит не в /etc/default (туда нет доступа без root), а в
# /opt/gendesign/secrets — путь передаётся переменной.
15 4 * * * FORGEJO_BACKUP_ENV_FILE=/opt/gendesign/secrets/forgejo-backup.env bash /opt/gendesign/ops/backup-forgejo.sh >> /opt/gendesign/logs/backup-forgejo.log 2>&1
# Сторож пропущенных прогонов для forgejo-бэкапа. Порог 26ч.
0 * * * * bash /opt/gendesign/ops/check-backup-staleness.sh /opt/gendesign/backups/forgejo/.last_success 26 "forgejo backup" >> /opt/gendesign/logs/backup-staleness.log 2>&1
# ── Уборка докера ───────────────────────────────────────────────────────────
# Остаётся здесь, потому что здесь остаются CI-раннеры (#2881) — именно их
# тома и растут. На Selectel нужна СВОЯ такая же запись (см. crontab-poincare).
0 4 * * 0 bash /opt/gendesign/ops/docker-prune.sh >> /tmp/gendesign-docker-prune.log 2>&1
# ── ЧТО ОТСЮДА УБРАНО И ПОЧЕМУ ──────────────────────────────────────────────
# Все записи ниже переехали в ops/crontab-poincare.cron, потому что обращаются
# к контейнерам и данным, которых на Beget после переезда не будет:
#
# 30 4 * * * backup-tradein-db.sh -> dump из tradein-postgres
# 30 3 * * * ops/backup.sh -> dump из gendesign-postgres
# 0 5 * * * backfill_houses_dadata -> docker exec tradein-backend
# 30 5 * * * geocode_deals_from_houses -> docker exec tradein-backend
# 45 5 * * * geocode_deals_nominatim -> docker exec tradein-backend
# 0 * * * * staleness: backups/.last_success (main-бэкап уехал)
# 0 * * * * staleness: backups/tradein/.last_success (tradein-бэкап уехал)
#
# ⚠️ Оставить их здесь = пять падающих задач в сутки И потерянные бэкапы
# обоих продуктовых кластеров.

48
ops/crontab-poincare.cron Normal file
View file

@ -0,0 +1,48 @@
# crontab ПРИНИМАЮЩЕГО хоста (Selectel Poincare, 188.246.224.93) — после 30.08.
#
# Устанавливать СРАЗУ после того, как стек поднялся и смоук прошёл:
# crontab /opt/gendesign/ops/crontab-poincare.cron
# crontab -l # сверить
#
# ⚠️ САМЫЙ ОПАСНЫЙ ПРОПУСК ВСЕГО ПЕРЕЕЗДА. Если этот файл не установить,
# на новом хосте НЕ БУДЕТ НИ ОДНОГО БЭКАПА — ни tradein, ни gendesign. И узнать
# об этом будет неоткуда: сторож пропущенных прогонов (check-backup-staleness)
# сам живёт в этом же crontab'е, то есть его тоже не будет. Отсутствие бэкапов
# обнаружится в момент, когда они понадобятся.
#
# Времена оставлены те же, что были на Beget — чтобы не гадать, изменилось ли
# поведение из-за переезда или из-за нового расписания. Подгонять окна имеет
# смысл ПОСЛЕ того, как всё поедет стабильно.
# ── Бэкапы обоих кластеров ──────────────────────────────────────────────────
# Off-box выгрузка в S3 включается через /etc/default/tradein-backup и
# /etc/default/gendesign-backup — файлы НЕ переезжают сами (в git их нет и не
# должно быть), их нужно перенести руками. Без них дампы останутся локальными,
# то есть на том же диске, что и БД, — ровно то, из-за чего заводился #2203.
30 3 * * * bash /opt/gendesign/ops/backup.sh >> /opt/gendesign/logs/gendesign-backup.log 2>&1
30 4 * * * bash /opt/gendesign/tradein-mvp/deploy/backup-tradein-db.sh >> /opt/gendesign/logs/tradein-backup.log 2>&1
# Сторожа пропущенных прогонов, порог 26ч. Едут вместе со своими бэкапами:
# сторож должен жить там же, где sentinel, иначе он сторожит файл, который
# никто не обновляет, и кричит вечно.
0 * * * * bash /opt/gendesign/ops/check-backup-staleness.sh /opt/gendesign/backups/.last_success 26 "gendesign main backup" >> /opt/gendesign/logs/backup-staleness.log 2>&1
0 * * * * bash /opt/gendesign/ops/check-backup-staleness.sh /opt/gendesign/backups/tradein/.last_success 26 "tradein backup" >> /opt/gendesign/logs/backup-staleness.log 2>&1
# ── Обогащение и геокодирование (ходят в tradein-backend) ───────────────────
0 5 * * * cd /opt/gendesign/tradein-mvp && docker exec tradein-backend python -m scripts.backfill_houses_dadata --limit 100 --priority both >> /opt/gendesign/logs/dadata-backfill.log 2>&1
30 5 * * * cd /opt/gendesign/tradein-mvp && docker exec tradein-backend python -m scripts.geocode_deals_from_houses --limit 50000 >> /opt/gendesign/logs/deals-geocode.log 2>&1
45 5 * * * cd /opt/gendesign/tradein-mvp && docker exec tradein-backend python -m scripts.geocode_deals_nominatim --limit 5000 >> /opt/gendesign/logs/deals-nominatim.log 2>&1
# ── Уборка докера ───────────────────────────────────────────────────────────
# СВОЯ запись, не «переехавшая»: на Beget она чистит тома CI-раннеров, здесь —
# образы продуктового стека. Нужны обе, на обоих хостах.
0 4 * * 0 bash /opt/gendesign/ops/docker-prune.sh >> /opt/gendesign/logs/docker-prune.log 2>&1
# ── Логи: /opt/gendesign/logs, а не /tmp ────────────────────────────────────
# На Beget половина записей писала в /tmp — он чистится при перезагрузке, и
# именно поэтому историю отказов бэкапов там восстановить не удавалось.
# Каталог создать до установки crontab: mkdir -p /opt/gendesign/logs
#
# ── ЧЕГО ЗДЕСЬ НЕТ ──────────────────────────────────────────────────────────
# backup-forgejo.sh + его сторож — Forgejo остаётся на Beget
# (см. ops/crontab-beget.cron)