Деплой прошёл, smoke покраснел, в журнале исключения, пользователи пишут. В этот момент нужен не поиск бага, а возврат к рабочей версии. Поиском займётесь потом. Этот план работает, если заранее подготовлены три вещи из урока о деплое без git: снапшоты кода на сервере, файл REVISION и бэкап БД перед миграциями.
Минута 0: не чинить вперёд
Главный соблазн — «сейчас быстро поправлю и задеплою ещё раз». Это занимает 10–30 минут, и сайт всё это время лежит. Хотфикс может сломать что-то ещё. Правило простое: сначала откат, потом разбор. Исключение одно: ошибка тривиальная (опечатка в конфиге), и исправление очевидно короче отката.
Минута 1: что сейчас на проде
ssh deploy@example.com 'cat /srv/myproject/app/REVISION; ls -1dt /srv/myproject/deploy-snapshots/* | head -3'
ssh deploy@example.com 'journalctl --user -u myproject -n 50 --no-pager'
Убедитесь, что сломал именно последний деплой (sha в REVISION совпадает с только что залитым), и найдите снапшот, на который откатываться.
Минута 2: откат кода
Схема со снапшотами (rsync + hardlinks):
./scripts/push.sh --rollback
# под капотом: rsync -a --delete <последний снапшот>/ <каталог сайта>/ + рестарт сервисов
Схема releases/ + current:
ssh deploy@example.com bash -s <<'EOF'
set -euo pipefail
cd /srv/myproject
prev="$(ls -1dt releases/*/ | sed -n 2p)"
ln -sfn "$PWD/$prev" current.new && mv -Tf current.new current
systemctl --user restart myproject
echo "откат на $prev"
EOF
Если отдельного скрипта нет, а git-репозиторий под рукой, сделайте git checkout <предыдущий sha> локально и обычный деплой. Это дольше, но тоже работает.
Отдельные случаи:
- Изменились зависимости (venv,
node_modules, NuGet): если они не входят в снапшот, переустановите их по lock-файлу откаченной версии. - Фронт с хешированными бандлами: у пользователей могут быть открыты страницы, которые ссылаются на новые бандлы. Не удаляйте новые файлы сразу, пусть полежат до следующего деплоя.
- Кэш: если новый код записал в кэш данные в новом формате, сбросьте только префикс приложения, не весь Redis (иначе потеряете сессии, счётчики rate-limit и данные соседних сервисов).
Минута 3: проверка
for i in $(seq 1 20); do curl -fsS -o /dev/null https://example.com/health/ && break; sleep 1; done
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/
ssh deploy@example.com 'cat /srv/myproject/app/REVISION'
Убедитесь, что REVISION показывает старый sha, ключевые страницы отвечают 200, а в журнале нет новых ошибок.
А что с базой данных
Откат кода не откатывает миграции. Варианты по степени тяжести:
- Миграция обратно совместима (expand/contract: добавили колонку или таблицу, ничего не удалили). Старый код работает с новой схемой, БД не трогаем. Поэтому именно так и пишут миграции.
- Миграция несовместима, но обратима. Выполните обратную миграцию на версии, которая её содержит (
manage.py migrate app 0041,dotnet ef database update PreviousMigration,php artisan migrate:rollback --step=1), до отката кода, иначе в старом коде этих миграций уже нет. - Миграция удалила данные. Восстанавливайте из дампа, снятого перед миграцией. Если после деплоя прошло время, сначала восстановите дамп в отдельную БД и перенесите нужные таблицы или строки, а не перезаписывайте целиком: иначе потеряете заказы, сделанные за это время.
createdb myproject_before
pg_restore -d myproject_before --no-owner ~/backups/myproject/db/myproject-*-pre-migrate.dump
После аварии
- Запишите в двух-трёх строках, что сломалось, как заметили, сколько длилось и что изменить.
- Добавьте проверку, которая поймала бы эту поломку до прода: тест, шаг CI, пункт smoke.
- Если откат шёл медленно или вручную, автоматизируйте его: при неудачном health-check деплой-скрипт сам переключается обратно.
- Хотя бы раз отрепетируйте откат на тестовом сервере. Откат, который ни разу не запускали, работает так же надёжно, как бэкап, который ни разу не восстанавливали.
Шпаргалка
- [ ] Не чинить вперёд, сначала откатить.
- [ ] Посмотреть
REVISIONи журнал, найти снапшот или предыдущий релиз. - [ ] Откатить код одной командой, переустановить зависимости при необходимости.
- [ ] Дождаться
/health/, проверить ключевые страницы иREVISION. - [ ] БД: совместима — не трогать; обратима — откатить миграцию; данные потеряны — восстановить из pre-migrate дампа выборочно.
- [ ] Короткий разбор и новая проверка, которая поймала бы проблему.
