Files
microfish/backend/docker_entrypoint.sh
Kunthawat Greethong 8953b8f066 fix: ensure Postgres driver installs in image & stop uv re-sync at runtime
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.
2026-08-31 18:56:18 +07:00

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