fix: automatic DB migration — run before backend starts
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 3s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 3s
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 <noreply@anthropic.com>
This commit is contained in:
@@ -42,23 +42,23 @@ jobs:
|
|||||||
|
|
||||||
docker compose exec -T postgres pg_dumpall -U translate | gzip > "$BACKUP_FILE"
|
docker compose exec -T postgres pg_dumpall -U translate | gzip > "$BACKUP_FILE"
|
||||||
BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
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
|
# Keep only last 10 backups
|
||||||
ls -t "${BACKUP_DIR}"/translate_db_*.sql.gz | tail -n +11 | xargs -r rm --
|
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 ==="
|
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 ==="
|
echo "=== [4/8] Starting postgres and redis ==="
|
||||||
docker compose up -d --remove-orphans
|
docker compose up -d postgres redis
|
||||||
|
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
# 5. WAIT FOR POSTGRES
|
# 5. WAIT FOR POSTGRES
|
||||||
@@ -66,11 +66,11 @@ jobs:
|
|||||||
echo "=== [5/8] Waiting for postgres ==="
|
echo "=== [5/8] Waiting for postgres ==="
|
||||||
for i in $(seq 1 30); do
|
for i in $(seq 1 30); do
|
||||||
if docker compose exec -T postgres pg_isready -U translate >/dev/null 2>&1; then
|
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
|
break
|
||||||
fi
|
fi
|
||||||
if [ "$i" -eq 30 ]; then
|
if [ "$i" -eq 30 ]; then
|
||||||
echo " ❌ Postgres not ready after 60s"
|
echo " FATAL: Postgres not ready after 60s"
|
||||||
docker compose logs postgres --tail=30
|
docker compose logs postgres --tail=30
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -78,38 +78,40 @@ jobs:
|
|||||||
done
|
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 ==="
|
echo "=== [6/8] Running database migrations ==="
|
||||||
if ! docker compose run --rm backend alembic upgrade head; then
|
if ! docker compose run --rm backend alembic upgrade head; then
|
||||||
echo " ❌ Migration FAILED!"
|
echo " FATAL: Migration FAILED!"
|
||||||
echo " ⚠️ Restoring database from backup..."
|
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
|
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..."
|
echo " Database restored."
|
||||||
docker compose restart backend
|
echo " Deploy ABORTED."
|
||||||
echo " ❌ Deploy aborted. Database restored from backup."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo " ✅ Migrations applied"
|
echo " Migrations applied successfully"
|
||||||
|
|
||||||
# Restart backend to pick up new schema
|
|
||||||
docker compose restart backend
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
# 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
|
for i in $(seq 1 20); do
|
||||||
if curl -sf http://localhost:8001/health >/dev/null 2>&1; then
|
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
|
break
|
||||||
fi
|
fi
|
||||||
if [ "$i" -eq 20 ]; then
|
if [ "$i" -eq 20 ]; then
|
||||||
echo " ❌ Backend not healthy after 100s"
|
echo " FATAL: Backend not healthy after 100s"
|
||||||
echo " ⚠️ Rolling back database..."
|
echo " Rolling back database..."
|
||||||
gunzip -c "$BACKUP_FILE" | docker compose exec -T postgres psql -U translate -d translate_db >/dev/null 2>&1 || true
|
gunzip -c "$BACKUP_FILE" | docker compose exec -T postgres psql -U translate -d translate_db >/dev/null 2>&1 || true
|
||||||
docker compose restart backend
|
docker compose restart backend
|
||||||
echo " ❌ Deploy failed. Database restored."
|
echo " Deploy FAILED. Database restored."
|
||||||
docker compose logs backend --tail=50
|
docker compose logs backend --tail=50
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
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..."
|
echo "🚀 Starting Document Translation API..."
|
||||||
|
|
||||||
# Wait for database to be ready (if DATABASE_URL is set)
|
# Wait for database to be ready (if DATABASE_URL is set)
|
||||||
@@ -42,7 +48,7 @@ except:
|
|||||||
|
|
||||||
# Run database migrations
|
# Run database migrations
|
||||||
echo "📦 Running database migrations..."
|
echo "📦 Running database migrations..."
|
||||||
alembic upgrade head || echo "⚠️ Migration skipped (may already be up to date)"
|
alembic upgrade head
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Wait for Redis if configured
|
# Wait for Redis if configured
|
||||||
|
|||||||
Reference in New Issue
Block a user