#!/usr/bin/env bash # Pull the latest code and restart Thermograph. Run on the VPS — the GitHub # Actions workflow invokes this over SSH, and you can run it by hand too. # # ssh deploy@vps '/opt/thermograph/deploy/deploy.sh' set -euo pipefail APP_DIR="${APP_DIR:-/opt/thermograph}" BRANCH="${BRANCH:-main}" cd "$APP_DIR" # Pre-warm the ~750 city-page archives so /climate pages serve from cache and a # search-engine crawl never bursts the archive API quota. Detached + backgrounded # so it never blocks the deploy or health check; idempotent (skips already-cached # cells), so it's cheap on every deploy after the first full warm. warm_city_archives() { mkdir -p "$APP_DIR/logs" echo "==> Warming city-page archives in the background (logs/warm-cities.log)" setsid nohup bash -c "cd '$APP_DIR/backend' && exec '$APP_DIR/.venv/bin/python' warm_cities.py --pace 2" \ "$APP_DIR/logs/warm-cities.log" 2>&1 & } # Notify IndexNow (Bing / DuckDuckGo / Yandex) of the site's URLs, but only when # the set of pages actually changed (a new/removed city) — code-only deploys skip, # so we don't re-blast ~14k URLs every push. Best-effort: never fails the deploy. # Sourcing the env matches the key the running service serves at /{key}.txt. ping_indexnow() { echo "==> Pinging IndexNow (only if the URL set changed)" ( set -a; . /etc/thermograph.env 2>/dev/null || true; set +a base="${THERMOGRAPH_BASE_URL:-https://thermograph.org}" cd "$APP_DIR/backend" && "$APP_DIR/.venv/bin/python" indexnow.py --if-changed "$base" ) || echo "!! IndexNow ping failed (non-fatal)" >&2 } echo "==> Fetching $BRANCH" git fetch --prune origin "$BRANCH" git reset --hard "origin/$BRANCH" echo "==> Installing dependencies" if [ ! -d .venv ]; then python3 -m venv .venv fi .venv/bin/pip install --upgrade pip -q .venv/bin/pip install -r backend/requirements.txt -q # Apply any pending accounts-DB schema migrations before the new code starts, so # it never queries a column an older database lacks. Idempotent and tracked, so # every deploy can run it; sourcing the env picks up a THERMOGRAPH_ACCOUNTS_DB # override if one is set. Runs as the deploy user, who owns the data dir. echo "==> Applying database migrations" ( set -a; . /etc/thermograph.env 2>/dev/null || true; set +a "$APP_DIR/.venv/bin/python" "$APP_DIR/deploy/migrate-db.py" ) echo "==> Restarting service" sudo systemctl restart thermograph echo "==> Health check" PORT="$(sed -n 's/^PORT=//p' /etc/thermograph.env)"; PORT="${PORT:-8137}" BASE="$(sed -n 's/^THERMOGRAPH_BASE=//p' /etc/thermograph.env)"; BASE="${BASE:-/}" # Normalize: no double slash, allow root. url="http://127.0.0.1:${PORT}${BASE%/}/" for i in $(seq 1 15); do if curl -fsS -o /dev/null "$url"; then echo "==> OK: $url is serving" warm_city_archives ping_indexnow exit 0 fi sleep 1 done echo "!! Health check failed for $url" >&2 sudo systemctl status thermograph --no-pager -l || true exit 1