Защита бэкапов от пустой БД пропускает БД без таблиц (счётчики «?») (#74) #100
+12
-5
@@ -737,16 +737,23 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. Дождитесь, пока приложение создаст пустую БД (`docker compose ps` → `app` `(healthy)`).
|
3. Дождитесь, пока приложение создаст пустую БД (`docker compose ps` → `app` `(healthy)`).
|
||||||
Контейнер `backup` стартует одновременно с `app` и сразу пробует сделать первый бэкап. В его
|
Контейнер `backup` стартует одновременно с `app`, ждёт, пока приложение ответит (до
|
||||||
журнале (`docker compose logs backup`) нормально увидеть одно из двух:
|
10 минут), и пробует сделать первый бэкап. В его журнале (`docker compose logs backup`)
|
||||||
|
нормально увидеть одно из трёх:
|
||||||
|
|
||||||
- если `backup` успел раньше, чем `app` создал БД:
|
- если приложение так и не поднялось и БД нет:
|
||||||
|
|
||||||
```
|
```
|
||||||
ОШИБКА: БД /fs-db/forbidden_stars.db не найдена — приложение ещё ни разу не запускалось?
|
ОШИБКА: БД /fs-db/forbidden_stars.db не найдена — приложение ещё ни разу не запускалось?
|
||||||
Первый бэкап не удался — следующая попытка по расписанию.
|
Первый бэкап не удался — следующая попытка по расписанию.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- если БД есть, но без таблиц (миграции ещё не прошли):
|
||||||
|
|
||||||
|
```
|
||||||
|
Не удалось прочитать число игроков и партий: в БД нет таблиц users/matches.
|
||||||
|
```
|
||||||
|
|
||||||
- если БД уже была:
|
- если БД уже была:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -763,8 +770,8 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
Проверьте, что у выбранного снимка в столбцах `Игроков`/`Партий` числа, а не `0` и не `?`.
|
Проверьте, что у выбранного снимка в столбцах `Игроков`/`Партий` числа, а не `0` и не `?`.
|
||||||
Защита выше не распознаёт БД без таблиц: если первый бэкап попал ровно в момент создания
|
Снимки без данных защита больше не создаёт, но снимок с `?` мог остаться от старой версии
|
||||||
БД, в списке может появиться свежий снимок с `?` (задача #74). Такой снимок не выбирайте.
|
бэкапов — такой не выбирайте.
|
||||||
|
|
||||||
5. Восстановите, подставив ID из `list vps`:
|
5. Восстановите, подставив ID из `list vps`:
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,21 @@ if [ ! -s "$CRONTAB" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! fs-backup has-snapshots; then
|
if ! fs-backup has-snapshots; then
|
||||||
log "Снимков в локальном репозитории ещё нет — делаю первый бэкап сразу."
|
# Новый сервер: app и backup стартуют разом, и БД может быть ещё без таблиц. /api/health
|
||||||
|
# отвечает только после миграций и bootstrap — ждём его (#74). Не дождались — пробуем всё
|
||||||
|
# равно: guard_empty не сохранит БД без таблиц.
|
||||||
|
_app="${BACKUP_APP_HOST:-app}"
|
||||||
|
_wait="${BACKUP_APP_WAIT_SECONDS:-600}"
|
||||||
|
log "Снимков в локальном репозитории ещё нет — жду приложение (до ${_wait} с) и делаю первый бэкап."
|
||||||
|
_waited=0
|
||||||
|
until wget -q -T 3 -O /dev/null "http://$_app:8000/api/health" 2>/dev/null; do
|
||||||
|
if [ "$_waited" -ge "$_wait" ]; then
|
||||||
|
log "Приложение не ответило за ${_wait} с — пробую бэкап без него."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
_waited=$((_waited + 10))
|
||||||
|
done
|
||||||
fs-backup run --scheduled || log "Первый бэкап не удался — следующая попытка по расписанию."
|
fs-backup run --scheduled || log "Первый бэкап не удался — следующая попытка по расписанию."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -178,6 +178,17 @@ forget_repo() {
|
|||||||
# Защита истории от пустых данных: новый Pi до восстановления или случайно очищенная БД не
|
# Защита истории от пустых данных: новый Pi до восстановления или случайно очищенная БД не
|
||||||
# должны становиться «последним снимком» (restore latest вернул бы пустоту).
|
# должны становиться «последним снимком» (restore latest вернул бы пустоту).
|
||||||
guard_empty() { # guard_empty <игроков> <партий>
|
guard_empty() { # guard_empty <игроков> <партий>
|
||||||
|
# «?» — счётчики не прочитались: в БД нет таблиц (миграции ещё не прошли). Такой снимок
|
||||||
|
# стал бы latest и сломал бы restore latest (#74) — отказ, как и для пустой БД.
|
||||||
|
case "$1$2" in
|
||||||
|
*'?'*)
|
||||||
|
for _r in $(repos); do mark "run-$_r" err "в БД нет таблиц users/matches — бэкап не сделан"; done
|
||||||
|
log "Не удалось прочитать число игроков и партий: в БД нет таблиц users/matches."
|
||||||
|
log "Похоже, приложение ещё не применило миграции. Бэкап НЕ сделан, чтобы снимок без данных"
|
||||||
|
log "не стал последним. Дождитесь запуска приложения; если так и задумано:"
|
||||||
|
die "fs-backup run --allow-empty"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
if [ "$1" != 0 ] || [ "$2" != 0 ]; then return 0; fi
|
if [ "$1" != 0 ] || [ "$2" != 0 ]; then return 0; fi
|
||||||
for _repo in $(repos); do
|
for _repo in $(repos); do
|
||||||
_prev="$(r "$_repo" snapshots latest --host "$SNAP_HOST" --json 2>/dev/null | jq -r \
|
_prev="$(r "$_repo" snapshots latest --host "$SNAP_HOST" --json 2>/dev/null | jq -r \
|
||||||
|
|||||||
Reference in New Issue
Block a user