#!/bin/bash set -e wait_for_postgres() { if [ -z "$DATABASE_URL" ]; then return 0 fi echo "ctxd: waiting for PostgreSQL (DATABASE_URL is set)..." python3 <<'PY' import os, sys, time url = os.environ.get("DATABASE_URL", "") max_wait = int(os.environ.get("CTXD_PG_WAIT_SECONDS", "120")) interval = int(os.environ.get("CTXD_PG_WAIT_INTERVAL", "2")) deadline = time.time() + max_wait last_err = "" attempt = 0 while time.time() < deadline: attempt += 1 try: import psycopg conn = psycopg.connect(url, connect_timeout=5) conn.close() print("ctxd: PostgreSQL is ready") sys.exit(0) except Exception as e: last_err = str(e) if attempt == 1 or attempt % 10 == 0: print(f"ctxd: postgres not ready (attempt {attempt}): {last_err}", file=sys.stderr) time.sleep(interval) print("ctxd: FATAL: PostgreSQL not reachable within wait window.", file=sys.stderr) print(f"ctxd: last error: {last_err}", file=sys.stderr) print("ctxd:", file=sys.stderr) print("ctxd: Fix: start the full stack (postgres + ctxd), e.g.", file=sys.stderr) print("ctxd: cd app && docker compose up -d postgres ctxd", file=sys.stderr) print("ctxd:", file=sys.stderr) print("ctxd: Avoid: docker compose up -d --no-deps ctxd (skips postgres)", file=sys.stderr) print("ctxd: If postgres is on another host, fix DATABASE_URL / network.", file=sys.stderr) sys.exit(1) PY } wait_for_postgres # Initialize if needed if [ -n "$DATABASE_URL" ]; then # PostgreSQL mode — check if schema exists NEEDS_INIT=$(python3 -c " import psycopg, os, sys try: conn = psycopg.connect(os.environ['DATABASE_URL']) cur = conn.execute(\"SELECT EXISTS (SELECT FROM pg_tables WHERE schemaname='public' AND tablename='users')\") if not cur.fetchone()[0]: print('yes') else: print('no') except Exception: print('yes') " 2>/dev/null || echo "yes") if [ "$NEEDS_INIT" = "yes" ]; then echo "ctxd: initializing PostgreSQL database" python3 -m ctxd init --home "$CTXD_HOME" else echo "ctxd: running pending migrations" python3 -m ctxd.migrate_user_fk_set_null 2>&1 || echo "ctxd: migration warning (non-fatal)" fi else # SQLite mode — check for db file if [ ! -f "$CTXD_HOME/ctxd.db" ]; then echo "ctxd: initializing database at $CTXD_HOME" python3 -m ctxd init --home "$CTXD_HOME" fi fi echo "ctxd: starting daemon on ${CTXD_HOST:-0.0.0.0}:${CTXD_PORT:-9091}" exec python3 -m ctxd