#!/usr/bin/env bash # Boot script for the single-container HF Space: # 1. (only when no external DB is configured) start an in-container # PostgreSQL with pgvector and create the app's role/database/extensions, # 2. start Redis, # 3. start Ollama (embeddings), # 4. launch supervisord, which keeps the FastAPI app and Celery worker alive # and auto-restarts them if they crash or hang. set -euo pipefail PGBIN=/usr/lib/postgresql/16/bin # ── Database selection ──────────────────────────────────────────────────────── # When POSTGRES_HOST points at an external database (e.g. a managed Supabase # Postgres), we DON'T start the in-container Postgres — the app connects out # instead, and the data persists independently of this ephemeral container. # Only when the host is unset/localhost do we boot the bundled Postgres (the # local-dev / no-external-DB path). The app reads the same POSTGRES_* vars, so # nothing in the application code changes between the two modes. PGHOST_CFG="${POSTGRES_HOST:-localhost}" if [ -z "$PGHOST_CFG" ] || [ "$PGHOST_CFG" = "localhost" ] || [ "$PGHOST_CFG" = "127.0.0.1" ]; then USE_LOCAL_PG=1 else USE_LOCAL_PG=0 fi if [ "$USE_LOCAL_PG" = "1" ]; then PGDATA="/var/lib/postgresql/data" echo "[start] No external DB configured — starting in-container PostgreSQL at ephemeral $PGDATA (DB resets on restart)" export PGDATA PGUSER_DB="${POSTGRES_USER:-9xaipal}" PGPASS="${POSTGRES_PASSWORD:-9xaipal_dev_password}" PGDB="${POSTGRES_DB:-9xaipal}" PGPORT="${POSTGRES_PORT:-5432}" mkdir -p "$PGDATA" chown -R postgres:postgres "$(dirname "$PGDATA")" "$PGDATA" chmod 700 "$PGDATA" if [ ! -s "$PGDATA/PG_VERSION" ]; then echo "[start] Initializing PostgreSQL cluster at $PGDATA" su postgres -c "$PGBIN/initdb -D '$PGDATA' --auth-local=trust --auth-host=scram-sha-256 --encoding=UTF8" fi echo "[start] Starting PostgreSQL" su postgres -c "$PGBIN/pg_ctl -D '$PGDATA' -o '-c listen_addresses=localhost -p $PGPORT' -w -t 60 start" echo "[start] Ensuring role / database / extensions" # The role/database name can start with a digit (e.g. "9xaipal"), which is an # invalid *bare* SQL identifier — it must be double-quoted. Rather than fight # the nested shell quoting of `su postgres -c "psql -c \"...\""`, we write the # role SQL to a temp file: a file read by `psql -f` involves no shell, so the # double-quoted identifier (and a DO block) pass through verbatim. PG_INIT_SQL="$(mktemp /tmp/pg_init.XXXXXX.sql)" cat > "$PG_INIT_SQL" </tmp/ollama.log 2>&1 & for i in $(seq 1 30); do ollama list >/dev/null 2>&1 && break sleep 1 done if ollama list 2>/dev/null | grep -q qwen3-embedding; then echo "[start] Ollama ready; qwen3-embedding present" else echo "[start] WARNING: qwen3-embedding not found in Ollama; attempting pull" ollama pull qwen3-embedding || echo "[start] WARNING: pull failed; embeddings will be unavailable" fi echo "[start] Launching supervised services (API + Celery worker)" exec supervisord -c /code/supervisord.conf