9router / start.sh
hank-jay's picture
Backup config every minute and restore bucket root safely
24fba35 verified
Raw
History Blame Contribute Delete
3.13 kB
#!/bin/sh
# Jay 9router HF Space — bucket-sync wrapper entrypoint.
#
# Persists 9router SQLite config through HF Bucket. On boot, restore the latest
# SQLite snapshot from the bucket. While running, backup frequently so manual
# restarts do not lose freshly edited config. On shutdown, run one final
# best-effort backup before exiting.
set -eu
DATA_DIR="${DATA_DIR:-/app/data}"
HF_BUCKET_ID="${HF_BUCKET_ID:-hank-jay/9router-storage}"
HF_BUCKET_PREFIX="${HF_BUCKET_PREFIX:-}"
# Keep this short: config edits followed by quick restarts should not be lost.
SYNC_INTERVAL="${SYNC_INTERVAL:-60}"
INITIAL_SYNC_DELAY="${INITIAL_SYNC_DELAY:-10}"
RESTORE_DIR="$DATA_DIR/.bucket-restore"
mkdir -p "$DATA_DIR/db/backups"
APP_PID=""
SYNC_PID=""
bucket_uri() {
if [ -n "$HF_BUCKET_PREFIX" ]; then
printf 'hf://buckets/%s/%s' "$HF_BUCKET_ID" "$HF_BUCKET_PREFIX"
else
printf 'hf://buckets/%s' "$HF_BUCKET_ID"
fi
}
run_backup() {
if [ -z "${HF_TOKEN:-}" ]; then
echo "[sync] HF_TOKEN missing — skip backup" >&2
return 0
fi
if /opt/9router-sync/backup.sh; then
echo "[sync] backup ok"
else
echo "[sync] backup failed (will retry next interval)" >&2
return 1
fi
}
restore_from_bucket() {
if [ -z "${HF_TOKEN:-}" ]; then
return 0
fi
BUCKET_URI="$(bucket_uri)"
echo "[start] Pulling SQLite snapshot from bucket: $BUCKET_URI"
rm -rf "$RESTORE_DIR"
mkdir -p "$RESTORE_DIR" "$DATA_DIR/db"
# hf buckets sync is directory-oriented. Sync bucket root/prefix to a temp
# directory, then copy only the SQLite DB we need at runtime.
if hf buckets sync "$BUCKET_URI" "$RESTORE_DIR" >/dev/null 2>&1; then
if [ -s "$RESTORE_DIR/db/data.sqlite" ]; then
cp "$RESTORE_DIR/db/data.sqlite" "$DATA_DIR/db/data.sqlite"
echo "[start] Snapshot restored: $DATA_DIR/db/data.sqlite"
else
echo "[start] Bucket sync succeeded but db/data.sqlite missing — starting clean" >&2
fi
else
echo "[start] No prior snapshot in bucket (or restore failed) — starting clean"
fi
rm -rf "$RESTORE_DIR"
}
shutdown() {
echo "[start] shutdown signal received — final backup"
if [ -n "$SYNC_PID" ]; then
kill "$SYNC_PID" 2>/dev/null || true
fi
run_backup || true
if [ -n "$APP_PID" ]; then
kill "$APP_PID" 2>/dev/null || true
wait "$APP_PID" 2>/dev/null || true
fi
exit 0
}
trap shutdown INT TERM
if [ -z "${HF_TOKEN:-}" ]; then
echo "[start] WARNING: HF_TOKEN not set — running with EPHEMERAL data." >&2
echo "[start] Set HF_TOKEN as a Space secret to enable persistence." >&2
else
restore_from_bucket
(
sleep "$INITIAL_SYNC_DELAY"
run_backup || true
while true; do
sleep "$SYNC_INTERVAL"
run_backup || true
done
) &
SYNC_PID="$!"
fi
npm run start &
APP_PID="$!"
set +e
wait "$APP_PID"
APP_STATUS="$?"
set -e
if [ -n "$SYNC_PID" ]; then
kill "$SYNC_PID" 2>/dev/null || true
fi
run_backup || true
exit "$APP_STATUS"