Merge pull request 'feat(tradein): бэкап tradein-postgres по cron (#397)' (#412) from feat/tradein-db-backup into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Successful in 23s
Deploy Trade-In / build-backend (push) Successful in 23s
Deploy Trade-In / deploy (push) Successful in 16s

This commit is contained in:
lekss361 2026-05-22 06:23:35 +00:00
commit 4e36fcb0cc

View file

@ -0,0 +1,42 @@
#!/usr/bin/env bash
# Бэкап БД tradein-postgres — pg_dump по cron + retention (#397).
#
# Запускается из cron на прод-хосте. pg_dump идёт через `docker exec`
# (локальный сокет внутри контейнера — пароль не нужен).
#
# Crontab пример (ежедневно в 04:30 UTC):
# 30 4 * * * /opt/gendesign/tradein-mvp/deploy/backup-tradein-db.sh >> /tmp/tradein-backup.log 2>&1
#
# Restore:
# gunzip -c tradein-YYYYMMDD-HHMMSS.sql.gz | \
# docker exec -i tradein-postgres psql -U tradein -d tradein
set -euo pipefail
BACKUP_DIR="${BACKUP_DIR:-/opt/gendesign/backups/tradein}"
KEEP="${KEEP:-7}" # сколько копий хранить
PG_CONTAINER="${PG_CONTAINER:-tradein-postgres}"
mkdir -p "$BACKUP_DIR"
ts=$(date -u +'%Y%m%d-%H%M%S')
out="$BACKUP_DIR/tradein-$ts.sql.gz"
# --clean --if-exists → дамп самодостаточен для восстановления «с нуля».
# --no-owner → restore не требует тех же ролей.
docker exec "$PG_CONTAINER" pg_dump -U tradein -d tradein \
--no-owner --clean --if-exists 2>/dev/null | gzip -6 > "$out"
if [[ ! -s "$out" ]]; then
echo "[$(date -u +%H:%M:%S)] ОШИБКА: дамп пустой — $out" >&2
rm -f "$out"
exit 1
fi
# Retention — оставляем KEEP самых свежих, остальные tradein-*.sql.gz удаляем.
ls -1t "$BACKUP_DIR"/tradein-*.sql.gz 2>/dev/null \
| tail -n +"$((KEEP + 1))" \
| xargs -r rm -f
size=$(du -h "$out" | cut -f1)
count=$(ls -1 "$BACKUP_DIR"/tradein-*.sql.gz 2>/dev/null | wc -l | tr -d ' ')
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] backup ok: $out ($size), копий хранится: $count"