pahvalentines/deploy-backend-safe.sh
michael 3a6a8ba6e9 feat(deploy): add persistent Redis volume and queue-safe deploy script
Add a named volume for Redis so queue data survives container restarts.
Add deploy-backend-safe.sh that rebuilds and recreates only app/worker
containers while leaving db and redis untouched, preserving the queue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 10:15:08 -06:00

94 lines
2.6 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Redeploy backend services with latest code WITHOUT destroying
# the Redis queue (or Postgres data). Rebuilds and recreates only
# the app/worker containers, leaving db and redis untouched.
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="$ROOT_DIR/backend/docker-compose.yml"
ENV_FILE="$ROOT_DIR/backend/.env"
APP_SERVICES="web celery_worker_default celery_worker_video celery_beat"
# --- Preflight checks ---
if [ ! -d "$ROOT_DIR/.git" ]; then
echo "Error: run this script from the repo root (expected .git here)." >&2
exit 1
fi
if ! command -v docker >/dev/null 2>&1; then
echo "Error: docker is required but not found in PATH." >&2
exit 1
fi
if ! docker compose version >/dev/null 2>&1; then
echo "Error: docker compose is required but not available." >&2
exit 1
fi
if [ ! -f "$ENV_FILE" ]; then
echo "Error: environment variables not found at $ENV_FILE" >&2
exit 1
fi
if [ ! -f "$COMPOSE_FILE" ]; then
echo "Error: docker compose file not found at $COMPOSE_FILE" >&2
exit 1
fi
# --- Deploy ---
echo ""
echo "Pulling latest code..."
git -C "$ROOT_DIR" pull
echo ""
echo "Ensuring db and redis are running..."
docker compose -f "$COMPOSE_FILE" up -d db redis
echo ""
echo "Building app services (no cache)..."
docker compose -f "$COMPOSE_FILE" build --no-cache $APP_SERVICES
echo ""
echo "Recreating app services (redis & db untouched)..."
docker compose -f "$COMPOSE_FILE" up -d --force-recreate --no-deps $APP_SERVICES
echo ""
echo "Waiting for database to be healthy..."
MAX_ATTEMPTS=30
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
if docker compose -f "$COMPOSE_FILE" exec -T db pg_isready -U pah -d pah >/dev/null 2>&1; then
echo "Database is ready."
break
fi
ATTEMPT=$((ATTEMPT + 1))
if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then
echo "Error: database did not become healthy after $MAX_ATTEMPTS attempts." >&2
exit 1
fi
echo "Waiting for database... (attempt $ATTEMPT/$MAX_ATTEMPTS)"
sleep 2
done
echo ""
echo "Running database migrations..."
docker compose -f "$COMPOSE_FILE" exec -T web alembic upgrade head
echo ""
echo "Verifying Redis queue preserved..."
VIDEO_QUEUE=$(docker compose -f "$COMPOSE_FILE" exec -T redis redis-cli LLEN video 2>/dev/null || echo "?")
DEFAULT_QUEUE=$(docker compose -f "$COMPOSE_FILE" exec -T redis redis-cli LLEN celery 2>/dev/null || echo "?")
echo " video queue: $VIDEO_QUEUE tasks"
echo " default queue: $DEFAULT_QUEUE tasks"
echo ""
echo "Backend deploy complete (queue-safe)."