M19: harden performance and recovery
MobilityOps acceptance / backend (push) Canceled after 0s
MobilityOps acceptance / frontend (push) Canceled after 0s

This commit is contained in:
NuklearRabbit
2026-08-10 12:51:41 +02:00
parent fe06ff75a1
commit 5d7a5e7359
10 changed files with 164 additions and 42 deletions
+21
View File
@@ -52,3 +52,24 @@ docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml logs --tail
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec api alembic current
docker logs --tail=200 n8n
```
## Backup and restore
Create and structurally verify a timestamped PostgreSQL custom-format backup:
```bash
./deploy/unraid/backup-postgres.sh
```
Copy backups off the server according to the host backup policy. A restore is deliberately
guarded and creates an additional safety backup before replacing the database:
```bash
./deploy/unraid/restore-postgres.sh \
backups/postgres/mobilityops-YYYYMMDDTHHMMSSZ.dump \
RESTORE-MOBILITYOPS
```
The restore stops the API, recreates only the configured MobilityOps database, restarts
API/web and verifies the active Alembic revision. Test restores in a disposable environment
before using a production backup for incident recovery.
+23
View File
@@ -0,0 +1,23 @@
#!/bin/sh
set -eu
cd "$(dirname "$0")/../.."
project="${COMPOSE_PROJECT_NAME:-mobilityops}"
destination="${1:-backups/postgres}"
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
backup_file="${destination}/mobilityops-${timestamp}.dump"
temporary_file="${backup_file}.partial"
compose_files="-f compose.yaml -f compose.unraid.yaml"
mkdir -p "$destination"
trap 'rm -f "$temporary_file"' EXIT INT TERM
docker compose -p "$project" $compose_files exec -T db sh -eu -c \
'pg_dump --format=custom --no-owner --no-acl -U "$POSTGRES_USER" "$POSTGRES_DB"' \
> "$temporary_file"
docker compose -p "$project" $compose_files exec -T db pg_restore --list \
< "$temporary_file" > /dev/null
mv "$temporary_file" "$backup_file"
trap - EXIT INT TERM
printf '%s\n' "$backup_file"
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
set -eu
cd "$(dirname "$0")/../.."
backup_file="${1:-}"
confirmation="${2:-}"
project="${COMPOSE_PROJECT_NAME:-mobilityops}"
compose_files="-f compose.yaml -f compose.unraid.yaml"
if [ ! -f "$backup_file" ]; then
echo "Backup file not found: $backup_file" >&2
exit 1
fi
if [ "$confirmation" != "RESTORE-MOBILITYOPS" ]; then
echo "Refusing destructive restore; pass RESTORE-MOBILITYOPS as the second argument" >&2
exit 1
fi
docker compose -p "$project" $compose_files exec -T db pg_restore --list \
< "$backup_file" > /dev/null
safety_backup="$(./deploy/unraid/backup-postgres.sh)"
echo "Pre-restore safety backup: $safety_backup"
restart_api() {
docker compose -p "$project" $compose_files up -d api web > /dev/null
}
trap restart_api EXIT INT TERM
docker compose -p "$project" $compose_files stop api > /dev/null
docker compose -p "$project" $compose_files exec -T db sh -eu -c \
'dropdb --force -U "$POSTGRES_USER" "$POSTGRES_DB" && createdb -U "$POSTGRES_USER" "$POSTGRES_DB"'
docker compose -p "$project" $compose_files exec -T db sh -eu -c \
'pg_restore --no-owner --no-acl -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
< "$backup_file"
restart_api
trap - EXIT INT TERM
docker compose -p "$project" $compose_files exec -T api alembic current
echo "Restore completed from $backup_file"