67 lines
2.4 KiB
Bash
Executable file
67 lines
2.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Pull the latest code and roll the docker-compose stack (app + PostgreSQL). Run
|
|
# on the VPS — the Forgejo 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}"
|
|
HEALTH_PORT="${HEALTH_PORT:-8137}"
|
|
cd "$APP_DIR"
|
|
|
|
# Secrets (POSTGRES_PASSWORD, VAPID keys, AUTH_SECRET, ...) drive compose
|
|
# interpolation and are also loaded into the app container via env_file. Source
|
|
# them here so a by-hand run interpolates the same as the systemd unit does.
|
|
set -a; . /etc/thermograph.env 2>/dev/null || true; set +a
|
|
|
|
# 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 inside the app
|
|
# container (compose exec -d), idempotent (skips already-cached cells), so it
|
|
# never blocks the deploy or health check and is cheap on every deploy after the
|
|
# first full warm.
|
|
warm_city_archives() {
|
|
echo "==> Warming city-page archives in the background (app:/app/logs/warm-cities.log)"
|
|
docker compose exec -d app sh -c \
|
|
'python warm_cities.py --pace 2 >> /app/logs/warm-cities.log 2>&1' || true
|
|
}
|
|
|
|
# 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.
|
|
# Best-effort: never fails the deploy.
|
|
ping_indexnow() {
|
|
echo "==> Pinging IndexNow (only if the URL set changed)"
|
|
local base="${THERMOGRAPH_BASE_URL:-https://thermograph.org}"
|
|
docker compose exec -T app 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 "==> Building images"
|
|
docker compose build
|
|
|
|
# Schema migrations run inside the app container's entrypoint (alembic upgrade
|
|
# head) before uvicorn starts, so there's no separate migrate step or service
|
|
# restart here — compose owns the process model.
|
|
echo "==> Starting stack"
|
|
docker compose up -d
|
|
|
|
echo "==> Health check"
|
|
url="http://127.0.0.1:${HEALTH_PORT}/"
|
|
for i in $(seq 1 30); 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
|
|
docker compose ps || true
|
|
docker compose logs --tail=50 app || true
|
|
exit 1
|