diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 22d7b05..1d316cf 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -36,6 +36,43 @@ jobs: rm -rf /var/www/longde.cloud/* cp -r /tmp/web-projects/dist/* /var/www/longde.cloud/ + - name: Resolve stuck Prisma migrations + run: | + set -x + MYSQL_PASS=$(docker exec mysql-zhixi printenv MYSQL_PASSWORD 2>/dev/null || echo "Zhixi@2026!App") + MYSQL_EXEC="docker exec mysql-zhixi mysql -u zhixi_user -p'$MYSQL_PASS' zhixi" + + echo "=== Checking for failed migrations ===" + $MYSQL_EXEC -e "SELECT migration_name, applied_steps_count, rolled_back_at, SUBSTRING(logs, 1, 120) as logs_preview FROM _prisma_migrations ORDER BY started_at DESC LIMIT 5;" 2>/dev/null || echo "(could not query _prisma_migrations)" + + # Check for failed/stuck migrations + FAILED=$($MYSQL_EXEC -N -e "SELECT migration_name FROM _prisma_migrations WHERE logs LIKE '%failed%' LIMIT 1;" 2>/dev/null || true) + + if [ -n "$FAILED" ]; then + echo "[deploy] Found failed migration: $FAILED, cleaning up..." + + # Check what was partially created + echo "=== Checking partial state ===" + $MYSQL_EXEC -e "SELECT COUNT(*) AS cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA='zhixi' AND TABLE_NAME='AiUsageLog';" 2>/dev/null || true + $MYSQL_EXEC -e "SELECT COUNT(*) AS cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA='zhixi' AND TABLE_NAME='WaitlistEntry';" 2>/dev/null || true + $MYSQL_EXEC -e "SELECT COUNT(*) AS cnt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='zhixi' AND TABLE_NAME='UploadedFile' AND COLUMN_NAME='objectKey';" 2>/dev/null || true + + # Drop partially-created objects + $MYSQL_EXEC -e "DROP TABLE IF EXISTS AiUsageLog;" 2>/dev/null || true + $MYSQL_EXEC -e "DROP TABLE IF EXISTS WaitlistEntry;" 2>/dev/null || true + $MYSQL_EXEC -e "ALTER TABLE UploadedFile DROP COLUMN IF EXISTS objectKey;" 2>/dev/null || true + $MYSQL_EXEC -e "ALTER TABLE UploadedFile DROP COLUMN IF EXISTS bucket;" 2>/dev/null || true + $MYSQL_EXEC -e "DROP INDEX UploadedFile_objectKey_idx ON UploadedFile;" 2>/dev/null || true + + # Remove the failed migration record + $MYSQL_EXEC -e "DELETE FROM _prisma_migrations WHERE migration_name = '$FAILED';" + echo "[deploy] Deleted failed migration record: $FAILED" + else + echo "[deploy] No failed migrations found" + fi + + set +x + - name: Ensure API backend is running run: | set -x @@ -62,11 +99,26 @@ jobs: echo "=== Container status ===" docker ps -a --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null | grep -iE 'zhixi|mysql|redis' || true - # If API container exists but stopped, start it + # If API container exists but not running (stopped or restarting), handle it if docker ps -a --format '{{.Names}}' | grep -q '^zhixi-api$'; then - if ! docker ps --format '{{.Names}}' | grep -q '^zhixi-api$'; then - echo "[deploy] zhixi-api exists but stopped, starting..." - docker start zhixi-api 2>&1 || true + STATUS=$(docker ps -a --format '{{.Status}}' --filter name=zhixi-api) + if echo "$STATUS" | grep -q '^Up'; then + echo "[deploy] zhixi-api is already running" + else + echo "[deploy] zhixi-api status: $STATUS — stopping and recreating..." + docker stop zhixi-api 2>/dev/null || true + docker rm zhixi-api 2>/dev/null || true + # Rebuild image to pick up migration fixes + cd /tmp/api-server && docker build -t zhixi-api:latest . 2>&1 || true + ENV_FILE="" + [ -f /etc/zhixi/.env.production ] && ENV_FILE="--env-file /etc/zhixi/.env.production" + docker run -d \ + --name zhixi-api \ + --network zhixi-net \ + --restart unless-stopped \ + -p 3001:3000 \ + $ENV_FILE \ + zhixi-api:latest 2>&1 || true sleep 8 fi else