generated from john/python-template
Co-authored-by: Copilot App <[email protected]>
This commit is contained in:
co-authored by
Copilot App
parent
ca29bc8b74
commit
34c7b16675
@@ -9,51 +9,93 @@ SYNOLOGY_BACKUP_DIR="${SYNOLOGY_BACKUP_DIR:-}"
|
|||||||
|
|
||||||
timestamp="$(date -u +%Y%m%d-%H%M%S)"
|
timestamp="$(date -u +%Y%m%d-%H%M%S)"
|
||||||
postgres_file="postgres-${timestamp}.dump"
|
postgres_file="postgres-${timestamp}.dump"
|
||||||
uploads_file="uploads-${timestamp}.tar.gz"
|
|
||||||
config_file="config-${timestamp}.tar.gz"
|
config_file="config-${timestamp}.tar.gz"
|
||||||
|
logs_file="logs-${timestamp}.tar.gz"
|
||||||
manifest_file="backup-${timestamp}.manifest"
|
manifest_file="backup-${timestamp}.manifest"
|
||||||
|
|
||||||
mkdir -p "${BACKUP_DIR}"
|
mkdir -p "${BACKUP_DIR}"
|
||||||
|
|
||||||
|
# If SYNOLOGY_BACKUP_DIR wasn't exported in the shell, read it from ENV_FILE.
|
||||||
|
if [ -z "${SYNOLOGY_BACKUP_DIR}" ] && [ -f "${ENV_FILE}" ]; then
|
||||||
|
SYNOLOGY_BACKUP_DIR="$(
|
||||||
|
sed -n 's/^SYNOLOGY_BACKUP_DIR=//p' "${ENV_FILE}" | tail -n 1
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \
|
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \
|
||||||
"PGPASSWORD=\"\$POSTGRES_PASSWORD\" pg_dump -U \"\$POSTGRES_USER\" -d \"\$POSTGRES_DB\" -Fc" \
|
"PGPASSWORD=\"\$POSTGRES_PASSWORD\" pg_dump -U \"\$POSTGRES_USER\" -d \"\$POSTGRES_DB\" -Fc" \
|
||||||
> "${BACKUP_DIR}/${postgres_file}"
|
> "${BACKUP_DIR}/${postgres_file}"
|
||||||
|
|
||||||
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps --entrypoint sh app -lc \
|
|
||||||
"tar -C /app/uploads -czf - ." \
|
|
||||||
> "${BACKUP_DIR}/${uploads_file}"
|
|
||||||
|
|
||||||
tar -C . -czf "${BACKUP_DIR}/${config_file}" \
|
|
||||||
"${ENV_FILE}" \
|
|
||||||
"${COMPOSE_FILE}" \
|
|
||||||
deploy/cloudflared/config.yml
|
|
||||||
|
|
||||||
cat > "${BACKUP_DIR}/${manifest_file}" <<EOF
|
cat > "${BACKUP_DIR}/${manifest_file}" <<EOF
|
||||||
created_at_utc=${timestamp}
|
created_at_utc=${timestamp}
|
||||||
postgres_dump=${postgres_file}
|
postgres_dump=${postgres_file}
|
||||||
uploads_archive=${uploads_file}
|
backup_dir=${BACKUP_DIR}
|
||||||
config_archive=${config_file}
|
synology_backup_dir=${SYNOLOGY_BACKUP_DIR}
|
||||||
|
media_sync_mode=synology-incremental-new-files-only
|
||||||
compose_file=${COMPOSE_FILE}
|
compose_file=${COMPOSE_FILE}
|
||||||
env_file=${ENV_FILE}
|
env_file=${ENV_FILE}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
find "${BACKUP_DIR}" -type f \( \
|
find "${BACKUP_DIR}" -type f \( \
|
||||||
-name 'postgres-*.dump' -o \
|
-name 'postgres-*.dump' -o \
|
||||||
-name 'uploads-*.tar.gz' -o \
|
|
||||||
-name 'config-*.tar.gz' -o \
|
|
||||||
-name 'backup-*.manifest' \
|
-name 'backup-*.manifest' \
|
||||||
\) -mtime +"${RETENTION_DAYS}" -delete
|
\) -mtime +"${RETENTION_DAYS}" -delete
|
||||||
|
|
||||||
if [ -n "${SYNOLOGY_BACKUP_DIR}" ]; then
|
if [ -n "${SYNOLOGY_BACKUP_DIR}" ]; then
|
||||||
mkdir -p "${SYNOLOGY_BACKUP_DIR}"
|
mkdir -p "${SYNOLOGY_BACKUP_DIR}"
|
||||||
|
|
||||||
|
# 1) Always copy the PostgreSQL dump to Synology.
|
||||||
cp "${BACKUP_DIR}/${postgres_file}" "${SYNOLOGY_BACKUP_DIR}/${postgres_file}"
|
cp "${BACKUP_DIR}/${postgres_file}" "${SYNOLOGY_BACKUP_DIR}/${postgres_file}"
|
||||||
cp "${BACKUP_DIR}/${uploads_file}" "${SYNOLOGY_BACKUP_DIR}/${uploads_file}"
|
|
||||||
cp "${BACKUP_DIR}/${config_file}" "${SYNOLOGY_BACKUP_DIR}/${config_file}"
|
# 2) Snapshot deployment config and logs to Synology each run.
|
||||||
|
set -- "${ENV_FILE}" "${COMPOSE_FILE}"
|
||||||
|
if [ -f deploy/cloudflared/config.yml ]; then
|
||||||
|
set -- "$@" deploy/cloudflared/config.yml
|
||||||
|
fi
|
||||||
|
tar -C . -czf "${SYNOLOGY_BACKUP_DIR}/${config_file}" "$@"
|
||||||
|
|
||||||
|
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps \
|
||||||
|
-v "${SYNOLOGY_BACKUP_DIR}:/backup" \
|
||||||
|
--entrypoint sh app -lc \
|
||||||
|
"if [ -d /app/data/logs ]; then tar -C /app/data/logs -czf /backup/${logs_file} .; else : > /backup/${logs_file}; fi"
|
||||||
|
|
||||||
|
# 3) Sync uploads incrementally to Synology (copy only new files).
|
||||||
|
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps \
|
||||||
|
-v "${SYNOLOGY_BACKUP_DIR}:/backup" \
|
||||||
|
--entrypoint sh app -lc '
|
||||||
|
mkdir -p /backup/uploads/documents /backup/uploads/photos;
|
||||||
|
if [ -f /app/uploads/homepage.md ] && [ ! -f /backup/uploads/homepage.md ]; then
|
||||||
|
cp /app/uploads/homepage.md /backup/uploads/homepage.md;
|
||||||
|
fi;
|
||||||
|
if [ -d /app/uploads/documents ]; then
|
||||||
|
cp -an /app/uploads/documents/. /backup/uploads/documents/;
|
||||||
|
fi;
|
||||||
|
if [ -d /app/uploads/photos ]; then
|
||||||
|
cp -an /app/uploads/photos/. /backup/uploads/photos/;
|
||||||
|
fi
|
||||||
|
'
|
||||||
|
|
||||||
cp "${BACKUP_DIR}/${manifest_file}" "${SYNOLOGY_BACKUP_DIR}/${manifest_file}"
|
cp "${BACKUP_DIR}/${manifest_file}" "${SYNOLOGY_BACKUP_DIR}/${manifest_file}"
|
||||||
|
|
||||||
|
# Keep rolling dump/config/log/manifest snapshots on Synology.
|
||||||
|
find "${SYNOLOGY_BACKUP_DIR}" -maxdepth 1 -type f \( \
|
||||||
|
-name 'postgres-*.dump' -o \
|
||||||
|
-name 'config-*.tar.gz' -o \
|
||||||
|
-name 'logs-*.tar.gz' -o \
|
||||||
|
-name 'backup-*.manifest' \
|
||||||
|
\) -mtime +"${RETENTION_DAYS}" -delete
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Created backup set:"
|
echo "Created backup set:"
|
||||||
echo " ${BACKUP_DIR}/${postgres_file}"
|
echo " ${BACKUP_DIR}/${postgres_file}"
|
||||||
echo " ${BACKUP_DIR}/${uploads_file}"
|
|
||||||
echo " ${BACKUP_DIR}/${config_file}"
|
|
||||||
echo " ${BACKUP_DIR}/${manifest_file}"
|
echo " ${BACKUP_DIR}/${manifest_file}"
|
||||||
|
if [ -n "${SYNOLOGY_BACKUP_DIR}" ]; then
|
||||||
|
echo "Synology artifacts:"
|
||||||
|
echo " ${SYNOLOGY_BACKUP_DIR}/${postgres_file}"
|
||||||
|
echo " ${SYNOLOGY_BACKUP_DIR}/${config_file}"
|
||||||
|
echo " ${SYNOLOGY_BACKUP_DIR}/${logs_file}"
|
||||||
|
echo " ${SYNOLOGY_BACKUP_DIR}/uploads/{homepage.md,documents/,photos/} (incremental)"
|
||||||
|
echo " ${SYNOLOGY_BACKUP_DIR}/${manifest_file}"
|
||||||
|
else
|
||||||
|
echo "SYNOLOGY_BACKUP_DIR not set; skipped Synology copy."
|
||||||
|
fi
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ fi
|
|||||||
dump_file="$1"
|
dump_file="$1"
|
||||||
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.production.yml}"
|
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.production.yml}"
|
||||||
ENV_FILE="${ENV_FILE:-.env.production}"
|
ENV_FILE="${ENV_FILE:-.env.production}"
|
||||||
|
SYNOLOGY_BACKUP_DIR="${SYNOLOGY_BACKUP_DIR:-}"
|
||||||
|
|
||||||
if [ ! -f "${dump_file}" ]; then
|
if [ ! -f "${dump_file}" ]; then
|
||||||
echo "Backup file not found: ${dump_file}"
|
echo "Backup file not found: ${dump_file}"
|
||||||
@@ -20,7 +21,16 @@ backup_name="$(basename "${dump_file}")"
|
|||||||
timestamp="$(printf '%s' "${backup_name}" | sed -n 's/^postgres-\([0-9]\{8\}-[0-9]\{6\}\)\.dump$/\1/p')"
|
timestamp="$(printf '%s' "${backup_name}" | sed -n 's/^postgres-\([0-9]\{8\}-[0-9]\{6\}\)\.dump$/\1/p')"
|
||||||
uploads_file=""
|
uploads_file=""
|
||||||
config_file=""
|
config_file=""
|
||||||
|
|
||||||
|
# If SYNOLOGY_BACKUP_DIR wasn't exported in the shell, read it from ENV_FILE.
|
||||||
|
if [ -z "${SYNOLOGY_BACKUP_DIR}" ] && [ -f "${ENV_FILE}" ]; then
|
||||||
|
SYNOLOGY_BACKUP_DIR="$(
|
||||||
|
sed -n 's/^SYNOLOGY_BACKUP_DIR=//p' "${ENV_FILE}" | tail -n 1
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "${timestamp}" ]; then
|
if [ -n "${timestamp}" ]; then
|
||||||
|
# Legacy local full-archive naming.
|
||||||
candidate_uploads="${backup_dir}/uploads-${timestamp}.tar.gz"
|
candidate_uploads="${backup_dir}/uploads-${timestamp}.tar.gz"
|
||||||
candidate_config="${backup_dir}/config-${timestamp}.tar.gz"
|
candidate_config="${backup_dir}/config-${timestamp}.tar.gz"
|
||||||
if [ -f "${candidate_uploads}" ]; then
|
if [ -f "${candidate_uploads}" ]; then
|
||||||
@@ -40,19 +50,37 @@ docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh
|
|||||||
cat "${dump_file}" | docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \
|
cat "${dump_file}" | docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" exec -T postgres sh -lc \
|
||||||
"PGPASSWORD=\"\$POSTGRES_PASSWORD\" pg_restore -U \"\$POSTGRES_USER\" -d \"\$POSTGRES_DB\" --clean --if-exists --no-owner --no-privileges"
|
"PGPASSWORD=\"\$POSTGRES_PASSWORD\" pg_restore -U \"\$POSTGRES_USER\" -d \"\$POSTGRES_DB\" --clean --if-exists --no-owner --no-privileges"
|
||||||
|
|
||||||
if [ -n "${uploads_file}" ]; then
|
if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -d "${SYNOLOGY_BACKUP_DIR}/uploads" ]; then
|
||||||
|
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps \
|
||||||
|
-v "${SYNOLOGY_BACKUP_DIR}:/backup" \
|
||||||
|
--entrypoint sh app -lc \
|
||||||
|
"mkdir -p /app/uploads/documents /app/uploads/photos && \
|
||||||
|
find /app/uploads/documents -mindepth 1 -delete && \
|
||||||
|
find /app/uploads/photos -mindepth 1 -delete && \
|
||||||
|
if [ -d /backup/uploads/documents ]; then cp -a /backup/uploads/documents/. /app/uploads/documents/; fi && \
|
||||||
|
if [ -d /backup/uploads/photos ]; then cp -a /backup/uploads/photos/. /app/uploads/photos/; fi && \
|
||||||
|
if [ -f /backup/uploads/homepage.md ]; then cp /backup/uploads/homepage.md /app/uploads/homepage.md; else rm -f /app/uploads/homepage.md; fi"
|
||||||
|
elif [ -n "${uploads_file}" ]; then
|
||||||
|
# Legacy local full-archive restore.
|
||||||
cat "${uploads_file}" | docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps --entrypoint sh app -lc \
|
cat "${uploads_file}" | docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" run --rm --no-deps --entrypoint sh app -lc \
|
||||||
"mkdir -p /app/uploads && find /app/uploads -mindepth 1 -delete && tar -xzf - -C /app/uploads"
|
"mkdir -p /app/uploads && find /app/uploads -mindepth 1 -delete && tar -xzf - -C /app/uploads"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${config_file}" ]; then
|
if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -n "${timestamp}" ] && [ -f "${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" ]; then
|
||||||
|
tar -xzf "${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" -C .
|
||||||
|
elif [ -n "${config_file}" ]; then
|
||||||
|
# Legacy local full-archive restore.
|
||||||
tar -xzf "${config_file}" -C .
|
tar -xzf "${config_file}" -C .
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Restore complete from: ${dump_file}"
|
echo "Restore complete from: ${dump_file}"
|
||||||
if [ -n "${uploads_file}" ]; then
|
if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -d "${SYNOLOGY_BACKUP_DIR}/uploads" ]; then
|
||||||
|
echo "Restored uploads mirror from: ${SYNOLOGY_BACKUP_DIR}/uploads"
|
||||||
|
elif [ -n "${uploads_file}" ]; then
|
||||||
echo "Restored uploads archive: ${uploads_file}"
|
echo "Restored uploads archive: ${uploads_file}"
|
||||||
fi
|
fi
|
||||||
if [ -n "${config_file}" ]; then
|
if [ -n "${SYNOLOGY_BACKUP_DIR}" ] && [ -n "${timestamp}" ] && [ -f "${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz" ]; then
|
||||||
|
echo "Restored config archive: ${SYNOLOGY_BACKUP_DIR}/config-${timestamp}.tar.gz"
|
||||||
|
elif [ -n "${config_file}" ]; then
|
||||||
echo "Restored config archive: ${config_file}"
|
echo "Restored config archive: ${config_file}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
+17
-8
@@ -2,14 +2,21 @@
|
|||||||
|
|
||||||
This guide defines operational backup/restore for clean-slate recovery of the Docker runtime and Synology replication.
|
This guide defines operational backup/restore for clean-slate recovery of the Docker runtime and Synology replication.
|
||||||
|
|
||||||
## 1. Backup artifacts (full recovery set)
|
## 1. Backup artifacts (clean-slate recovery set)
|
||||||
|
|
||||||
- Primary local backup location: `./data/backups`
|
- Primary local backup location: `./data/backups`
|
||||||
- Files created per timestamp:
|
- Local files created per run:
|
||||||
- `postgres-YYYYMMDD-HHMMSS.dump` (PostgreSQL custom dump via `pg_dump -Fc`)
|
- `postgres-YYYYMMDD-HHMMSS.dump` (PostgreSQL custom dump via `pg_dump -Fc`)
|
||||||
- `uploads-YYYYMMDD-HHMMSS.tar.gz` (full `/app/uploads` volume; includes `homepage.md`, documents, and photos)
|
|
||||||
- `config-YYYYMMDD-HHMMSS.tar.gz` (deployment config snapshot: `.env.production`, `docker-compose.production.yml`, `deploy/cloudflared/config.yml`)
|
|
||||||
- `backup-YYYYMMDD-HHMMSS.manifest` (artifact index)
|
- `backup-YYYYMMDD-HHMMSS.manifest` (artifact index)
|
||||||
|
- Synology files created per run (when `SYNOLOGY_BACKUP_DIR` is set):
|
||||||
|
- `postgres-YYYYMMDD-HHMMSS.dump` (copied from local)
|
||||||
|
- `config-YYYYMMDD-HHMMSS.tar.gz` (deployment config snapshot: `.env.production`, `docker-compose.production.yml`, `deploy/cloudflared/config.yml` when present)
|
||||||
|
- `logs-YYYYMMDD-HHMMSS.tar.gz` (snapshot of `/app/data/logs`)
|
||||||
|
- `backup-YYYYMMDD-HHMMSS.manifest`
|
||||||
|
- Synology incremental media mirror (copied only if missing):
|
||||||
|
- `uploads/homepage.md`
|
||||||
|
- `uploads/documents/**`
|
||||||
|
- `uploads/photos/**`
|
||||||
|
|
||||||
## 2. Creating backups
|
## 2. Creating backups
|
||||||
|
|
||||||
@@ -23,14 +30,14 @@ Environment overrides:
|
|||||||
|
|
||||||
- `BACKUP_DIR` (default `./data/backups`)
|
- `BACKUP_DIR` (default `./data/backups`)
|
||||||
- `BACKUP_RETENTION_DAYS` (default `14`)
|
- `BACKUP_RETENTION_DAYS` (default `14`)
|
||||||
- `SYNOLOGY_BACKUP_DIR` (if set, backup is copied to this mounted path)
|
- `SYNOLOGY_BACKUP_DIR` (if set, dump/config/log/manifest are copied to this mounted path and media is synced incrementally)
|
||||||
- `ENV_FILE` (default `.env.production`)
|
- `ENV_FILE` (default `.env.production`)
|
||||||
- `COMPOSE_FILE` (default `docker-compose.production.yml`)
|
- `COMPOSE_FILE` (default `docker-compose.production.yml`)
|
||||||
|
|
||||||
Example with Synology mount:
|
Example with Synology mount:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
SYNOLOGY_BACKUP_DIR=/mnt/synology/transcription-backups sh deploy/backup/create_postgres_backup.sh
|
SYNOLOGY_BACKUP_DIR=/mnt/synology-backups sh deploy/backup/create_postgres_backup.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2.1 Persisting Synology mount (LXC)
|
## 2.1 Persisting Synology mount (LXC)
|
||||||
@@ -51,6 +58,7 @@ Recommended pattern:
|
|||||||
|
|
||||||
- Keep NAS credentials in a local file like `/etc/samba/credentials/transcription-synology` with `chmod 600`.
|
- Keep NAS credentials in a local file like `/etc/samba/credentials/transcription-synology` with `chmod 600`.
|
||||||
- Keep `SYNOLOGY_BACKUP_DIR` in `.env.production` aligned to that mount point (for example `/mnt/synology-backups`).
|
- Keep `SYNOLOGY_BACKUP_DIR` in `.env.production` aligned to that mount point (for example `/mnt/synology-backups`).
|
||||||
|
- The script will also read `SYNOLOGY_BACKUP_DIR` from `ENV_FILE` when not exported in the shell.
|
||||||
|
|
||||||
## 3. Restoring from backup
|
## 3. Restoring from backup
|
||||||
|
|
||||||
@@ -60,7 +68,8 @@ Restore requires downtime for app + worker writes.
|
|||||||
- `docker compose --env-file .env.production -f docker-compose.production.yml stop app worker`
|
- `docker compose --env-file .env.production -f docker-compose.production.yml stop app worker`
|
||||||
2. Restore:
|
2. Restore:
|
||||||
- `sh deploy/backup/restore_postgres_backup.sh ./data/backups/postgres-YYYYMMDD-HHMMSS.dump`
|
- `sh deploy/backup/restore_postgres_backup.sh ./data/backups/postgres-YYYYMMDD-HHMMSS.dump`
|
||||||
- if same-timestamp `uploads-*.tar.gz` and `config-*.tar.gz` exist in the same directory, they are restored automatically.
|
- if `SYNOLOGY_BACKUP_DIR/uploads` exists, media is restored from the Synology mirror.
|
||||||
|
- if `SYNOLOGY_BACKUP_DIR/config-YYYYMMDD-HHMMSS.tar.gz` exists, config is restored from that archive.
|
||||||
3. Start app and worker:
|
3. Start app and worker:
|
||||||
- `docker compose --env-file .env.production -f docker-compose.production.yml start app worker`
|
- `docker compose --env-file .env.production -f docker-compose.production.yml start app worker`
|
||||||
4. Validate `/healthz` and run one smoke workflow.
|
4. Validate `/healthz` and run one smoke workflow.
|
||||||
@@ -68,7 +77,7 @@ Restore requires downtime for app + worker writes.
|
|||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- Config restore extracts the archived files back into the current repository path.
|
- Config restore extracts the archived files back into the current repository path.
|
||||||
- If only the database dump is present, restore runs in database-only mode (legacy behavior).
|
- Legacy full-archive restores (`uploads-*.tar.gz`, `config-*.tar.gz` beside the dump) are still supported for older backups.
|
||||||
|
|
||||||
## 4. Retention and recovery targets
|
## 4. Retention and recovery targets
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ This runbook is the operational checklist for releasing and monitoring the trans
|
|||||||
- stdout aggregation receives events
|
- stdout aggregation receives events
|
||||||
- file logs are written under `./data/logs`
|
- file logs are written under `./data/logs`
|
||||||
5. Create a fresh PostgreSQL backup after successful deployment:
|
5. Create a fresh PostgreSQL backup after successful deployment:
|
||||||
- `sh deploy/backup/create_postgres_backup.sh` (creates DB dump + uploads + config recovery set)
|
- `sh deploy/backup/create_postgres_backup.sh` (creates local DB dump + Synology DB/config/log artifacts + incremental media mirror)
|
||||||
|
|
||||||
## 3. Rollback triggers and actions
|
## 3. Rollback triggers and actions
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ This runbook is the operational checklist for releasing and monitoring the trans
|
|||||||
- relevant DB rows (`job`, `job_source`, `execution_attempt`)
|
- relevant DB rows (`job`, `job_source`, `execution_attempt`)
|
||||||
5. If persistence regression is confirmed, restore the latest valid DB dump:
|
5. If persistence regression is confirmed, restore the latest valid DB dump:
|
||||||
- `sh deploy/backup/restore_postgres_backup.sh <dump-file>`
|
- `sh deploy/backup/restore_postgres_backup.sh <dump-file>`
|
||||||
- paired uploads/config artifacts (same timestamp) are restored automatically when present.
|
- Synology media mirror and paired config snapshot (same timestamp) are restored automatically when present.
|
||||||
|
|
||||||
## 4. Post-release monitoring checklist
|
## 4. Post-release monitoring checklist
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user