- backup service: nightly pg_dump with retention, recorded as a run
- GET /api/v1/status/sources: 503 when a scheduled source or the backup
missed its last two slots (for Uptime Kuma)
- worker logs to ${DATA_DIR}/logs, so they survive redeploys
- procurement: reject implausible award dates (1900, contract end dates),
skip placeholder contractors, credit framework agreements to the BBG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34 lines
1.3 KiB
Bash
34 lines
1.3 KiB
Bash
#!/bin/sh
|
|
# Nightly database backup, run by the `backup` service in docker-compose.yml.
|
|
# Writes politrack-YYYY-MM-DD.dump (pg_dump custom format) to /backups at 02:30 UTC, deletes dumps older than
|
|
# $BACKUP_KEEP_DAYS days, and records each attempt as a run of "backup", so /api/v1/status/sources alerts
|
|
# when backups stop. Restore: pg_restore -h <host> -U politrack -d politrack --clean <file>
|
|
set -u
|
|
KEEP="${BACKUP_KEEP_DAYS:-14}"
|
|
export PGHOST=db PGUSER=politrack PGDATABASE=politrack
|
|
|
|
record() { # record <status> <json stats>
|
|
psql -q -c "INSERT INTO run (adapter, mode, status, finished_at, stats) VALUES ('backup', 'backup', '$1', now(), '$2'::jsonb)" \
|
|
|| echo "could not record the backup run"
|
|
}
|
|
|
|
while true; do
|
|
now=$(date -u +%s)
|
|
next=$(date -u -d "today 02:30" +%s)
|
|
[ "$next" -le "$now" ] && next=$(date -u -d "tomorrow 02:30" +%s)
|
|
echo "next backup at $(date -u -d "@$next")"
|
|
sleep $((next - now))
|
|
|
|
file="/backups/politrack-$(date -u +%F).dump"
|
|
if pg_dump -Fc -f "$file.tmp" && mv "$file.tmp" "$file"; then
|
|
size=$(stat -c %s "$file")
|
|
echo "backup ok: $file ($size bytes)"
|
|
record ok "{\"file\": \"$(basename "$file")\", \"bytes\": $size}"
|
|
else
|
|
rm -f "$file.tmp"
|
|
echo "backup FAILED"
|
|
record error '{}'
|
|
fi
|
|
find /backups -name 'politrack-*.dump' -mtime "+$KEEP" -delete
|
|
done
|