#!/usr/bin/env bash # Deploy backend: build release, stop running process gracefully (PID file & pgrep fallback), rotate logs, and start via nohup # Usage: # ENV_FILE=prod ./scripts/deploy_backend.sh # ENV_FILE=staging ./scripts/deploy_backend.sh # Notes: # - ENV_FILE will be exported for the backend to decide which .env to load (e.g., .env.prod). # - PID is stored in backend/udmin.pid. set -euo pipefail # 获取脚本所在目录的绝对路径 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" BACKEND_DIR="$ROOT_DIR/backend" BIN_PATH="$BACKEND_DIR/target/release/udmin" LOG_FILE="$BACKEND_DIR/udmin.log" PID_FILE="$BACKEND_DIR/udmin.pid" ENV_FILE_VALUE="${ENV_FILE:-prod}" # 调试信息:打印关键路径 echo "[backend] Script directory: $SCRIPT_DIR" echo "[backend] Root directory: $ROOT_DIR" echo "[backend] Backend directory: $BACKEND_DIR" echo "[backend] Binary path: $BIN_PATH" # 检查关键目录是否存在 if [ ! -d "$BACKEND_DIR" ]; then echo "[backend] ERROR: Backend directory does not exist: $BACKEND_DIR" >&2 echo "[backend] Please ensure the script is placed in the correct location relative to the project structure" >&2 exit 1 fi if [ ! -f "$BACKEND_DIR/Cargo.toml" ]; then echo "[backend] ERROR: Cargo.toml not found in backend directory: $BACKEND_DIR" >&2 echo "[backend] This doesn't appear to be a valid Rust project directory" >&2 exit 1 fi cd "$BACKEND_DIR" echo "[backend] Building release binary..." cargo build --release if [ ! -x "$BIN_PATH" ]; then echo "[backend] ERROR: Binary not found or not executable: $BIN_PATH" >&2 exit 1 fi # Gracefully stop existing process (PID file first) stop_pid() { local pid="$1" if [ -z "$pid" ]; then return 0; fi if ! ps -p "$pid" >/dev/null 2>&1; then return 0; fi echo "[backend] Stopping udmin (pid=$pid) ..." kill -TERM "$pid" || true for i in {1..10}; do if ps -p "$pid" >/dev/null 2>&1; then sleep 1 else break fi done if ps -p "$pid" >/dev/null 2>&1; then echo "[backend] Force killing udmin (pid=$pid) ..." kill -KILL "$pid" || true fi } # 1) Stop by PID file if present echo "[backend] Checking for existing PID file: $PID_FILE" if [ -f "$PID_FILE" ]; then PID_CONTENT="$(cat "$PID_FILE" 2>/dev/null || true)" if [ -n "$PID_CONTENT" ]; then echo "[backend] Found PID file with PID: $PID_CONTENT" stop_pid "$PID_CONTENT" else echo "[backend] PID file exists but is empty" fi rm -f "$PID_FILE" echo "[backend] Removed PID file" else echo "[backend] No PID file found" fi # 2) Fallback: stop any process matching the release binary path (safe, avoids killing debug run) echo "[backend] Searching for existing processes matching: $BIN_PATH" PGREP_PIDS="$(pgrep -f "$BIN_PATH" 2>/dev/null || true)" if [ -n "$PGREP_PIDS" ]; then echo "[backend] Found existing udmin processes by path: $PGREP_PIDS" for p in $PGREP_PIDS; do echo "[backend] Stopping process: $p" stop_pid "$p" done else echo "[backend] No existing processes found matching the binary path" fi # Rotate log TS="$(date +%Y%m%d%H%M%S)" if [ -f "$LOG_FILE" ]; then mv "$LOG_FILE" "$LOG_FILE.$TS" || true fi echo "[backend] Starting udmin (ENV_FILE=$ENV_FILE_VALUE) ..." export ENV_FILE="$ENV_FILE_VALUE" nohup "$BIN_PATH" > "$LOG_FILE" 2>&1 & NEW_PID=$! echo "$NEW_PID" > "$PID_FILE" echo "[backend] Started with PID: $NEW_PID" echo "[backend] Logs: $LOG_FILE" echo "[backend] PID file: $PID_FILE" # 等待几秒钟验证进程是否成功启动 echo "[backend] Waiting 3 seconds to verify startup..." sleep 3 if ps -p "$NEW_PID" > /dev/null 2>&1; then echo "[backend] ✅ Process is running successfully (PID: $NEW_PID)" echo "[backend] Deployment completed successfully!" else echo "[backend] ❌ ERROR: Process failed to start or crashed immediately" >&2 echo "[backend] Check the log file for details: $LOG_FILE" >&2 if [ -f "$LOG_FILE" ]; then echo "[backend] Last few lines of log:" >&2 tail -10 "$LOG_FILE" >&2 fi exit 1 fi