Worker crash-loop root cause (from container log): sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres Two compounding issues: 1. Dockerfile copied pyproject.toml/uv.lock, ran 'uv sync --frozen', then 'COPY backend ./backend' which OVERWROTE those dep files with the shipped versions. The two could differ, so every entrypoint 'uv run' detected drift and REBUILT/re-synced the project at container runtime (seen as repeated 'Building crowdsight-backend...' + 'Uninstalled N / Installed 1'), never installing the psycopg Postgres driver that the image's own lock actually lists. 2. Result: alembic upgrade head over a postgres DATABASE_URL crashed with NoSuchModuleError -> worker crash-loop. Fix: - Dockerfile: COPY backend (full source) BEFORE 'uv sync --frozen --no-dev', so the installed deps match the shipped pyproject.toml/uv.lock exactly. - Use 'uv run --frozen' for alembic/gunicorn/worker so nothing re-syncs at runtime. - entrypoint: fail fast with a clear message if DATABASE_URL is postgres but psycopg is missing (instead of a confusing alembic traceback). Verified: entrypoint bash syntax ok; 'uv run --frozen ... import psycopg' passes; psycopg present in git-tracked uv.lock + pyproject.
37 lines
1.4 KiB
Bash
37 lines
1.4 KiB
Bash
#!/usr/bin/env bash
|
|
# Docker entrypoint for CrowdSight production image.
|
|
#
|
|
# Runs database migrations to head BEFORE starting any service, so that the
|
|
# backend (gunicorn) and the durable worker never query tables that do not
|
|
# exist yet (fixes worker crash-loop: "no such table: jobs").
|
|
#
|
|
# - Require DATABASE_URL to be set (fail fast with a clear message).
|
|
# - Run `alembic upgrade head` (idempotent; no-ops when already at head).
|
|
# - Then exec supervisord to run nginx + backend + worker.
|
|
|
|
set -euo pipefail
|
|
|
|
cd /app/backend
|
|
|
|
if [[ -z "${DATABASE_URL:-}" ]]; then
|
|
echo "[entrypoint] FATAL: DATABASE_URL is not set. Refusing to start." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# If DATABASE_URL points at Postgres, fail fast with a clear message if the
|
|
# psycopg driver is missing (instead of a confusing SQLAlchemy
|
|
# NoSuchModuleError inside alembic).
|
|
if [[ "$DATABASE_URL" == postgres* ]]; then
|
|
if ! uv run --frozen python -c "import psycopg" 2>/dev/null; then
|
|
echo "[entrypoint] FATAL: DATABASE_URL is PostgreSQL but the psycopg driver is not installed in this image. Rebuild the image so 'uv sync' installs psycopg[binary]." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo "[entrypoint] Running database migrations (alembic upgrade head)..."
|
|
uv run --frozen alembic upgrade head
|
|
echo "[entrypoint] Migrations complete."
|
|
|
|
echo "[entrypoint] Starting supervisord (nginx + backend + worker)..."
|
|
exec /usr/bin/supervisord -n
|