From 6c0ecded4744ca6687deeb80f13c755bee33d4e3 Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 17 May 2026 11:03:42 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20automatic=20DB=20migration=20=E2=80=94?= =?UTF-8?q?=20run=20before=20backend=20starts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three fixes to ensure alembic migrations always run in production: 1. entrypoint.sh: add `exec "$@"` passthrough so `docker compose run --rm backend alembic upgrade head` actually runs alembic instead of ignoring args and starting uvicorn. 2. entrypoint.sh: remove `|| echo` fallback on alembic — if migration fails the container must stop, not silently continue. 3. deploy.yml: start only postgres+redis first, run migration, THEN start backend. Previously the backend started before migration, ran with stale schema, and the separate migration step was broken by the entrypoint bug. Co-Authored-By: Claude Opus 4.7 --- .gitea/workflows/deploy.yml | 52 +++++++++++++++++++----------------- docker/backend/entrypoint.sh | 8 +++++- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 7b2680d..458f78c 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -42,23 +42,23 @@ jobs: docker compose exec -T postgres pg_dumpall -U translate | gzip > "$BACKUP_FILE" BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1) - echo " ✅ Backup saved: ${BACKUP_FILE} (${BACKUP_SIZE})" + echo " Backup saved: ${BACKUP_FILE} (${BACKUP_SIZE})" # Keep only last 10 backups ls -t "${BACKUP_DIR}"/translate_db_*.sql.gz | tail -n +11 | xargs -r rm -- - echo " 📦 Retained last 10 backups" + echo " Retained last 10 backups" # ────────────────────────────────────────────── - # 3. BUILD IMAGES + # 3. BUILD IMAGES (--no-cache for fresh deps) # ────────────────────────────────────────────── echo "=== [3/8] Building images ===" - docker compose build backend frontend + docker compose build --no-cache backend frontend # ────────────────────────────────────────────── - # 4. START SERVICES + # 4. START INFRASTRUCTURE ONLY (postgres + redis) # ────────────────────────────────────────────── - echo "=== [4/8] Starting services ===" - docker compose up -d --remove-orphans + echo "=== [4/8] Starting postgres and redis ===" + docker compose up -d postgres redis # ────────────────────────────────────────────── # 5. WAIT FOR POSTGRES @@ -66,11 +66,11 @@ jobs: echo "=== [5/8] Waiting for postgres ===" for i in $(seq 1 30); do if docker compose exec -T postgres pg_isready -U translate >/dev/null 2>&1; then - echo " ✅ Postgres ready after $((i * 2))s" + echo " Postgres ready after $((i * 2))s" break fi if [ "$i" -eq 30 ]; then - echo " ❌ Postgres not ready after 60s" + echo " FATAL: Postgres not ready after 60s" docker compose logs postgres --tail=30 exit 1 fi @@ -78,38 +78,40 @@ jobs: done # ────────────────────────────────────────────── - # 6. RUN MIGRATIONS (one-shot container) + # 6. RUN MIGRATIONS (BEFORE starting backend) + # entrypoint passes through args via exec "$@" # ────────────────────────────────────────────── echo "=== [6/8] Running database migrations ===" if ! docker compose run --rm backend alembic upgrade head; then - echo " ❌ Migration FAILED!" - echo " ⚠️ Restoring database from backup..." + echo " FATAL: Migration FAILED!" + echo " Restoring database from backup..." gunzip -c "$BACKUP_FILE" | docker compose exec -T postgres psql -U translate -d translate_db >/dev/null 2>&1 || true - echo " 🔄 Database restored. Restarting services..." - docker compose restart backend - echo " ❌ Deploy aborted. Database restored from backup." + echo " Database restored." + echo " Deploy ABORTED." exit 1 fi - echo " ✅ Migrations applied" - - # Restart backend to pick up new schema - docker compose restart backend + echo " Migrations applied successfully" # ────────────────────────────────────────────── - # 7. HEALTH CHECK + # 7. START ALL SERVICES (backend + frontend) + # backend entrypoint will see alembic is already at head → no-op # ────────────────────────────────────────────── - echo "=== [7/8] Waiting for backend healthy ===" + echo "=== [7/8] Starting all services ===" + docker compose up -d --remove-orphans + + # Wait for backend healthy + echo " Waiting for backend healthy..." for i in $(seq 1 20); do if curl -sf http://localhost:8001/health >/dev/null 2>&1; then - echo " ✅ Backend healthy after $((i * 5))s" + echo " Backend healthy after $((i * 5))s" break fi if [ "$i" -eq 20 ]; then - echo " ❌ Backend not healthy after 100s" - echo " ⚠️ Rolling back database..." + echo " FATAL: Backend not healthy after 100s" + echo " Rolling back database..." gunzip -c "$BACKUP_FILE" | docker compose exec -T postgres psql -U translate -d translate_db >/dev/null 2>&1 || true docker compose restart backend - echo " ❌ Deploy failed. Database restored." + echo " Deploy FAILED. Database restored." docker compose logs backend --tail=50 exit 1 fi diff --git a/docker/backend/entrypoint.sh b/docker/backend/entrypoint.sh index 982245a..e82bae9 100644 --- a/docker/backend/entrypoint.sh +++ b/docker/backend/entrypoint.sh @@ -1,6 +1,12 @@ #!/bin/bash set -e +# If a command is passed (e.g. `docker compose run --rm backend alembic upgrade head`), +# run it directly instead of the full startup sequence. +if [ $# -gt 0 ]; then + exec "$@" +fi + echo "🚀 Starting Document Translation API..." # Wait for database to be ready (if DATABASE_URL is set) @@ -42,7 +48,7 @@ except: # Run database migrations echo "📦 Running database migrations..." - alembic upgrade head || echo "⚠️ Migration skipped (may already be up to date)" + alembic upgrade head fi # Wait for Redis if configured