#!/bin/bash # AO3 Mirror - 启动脚本 # 启动 4 个 uvicorn worker 进程 + Caddy 负载均衡 set -e BASE_DIR="/home/ubuntu/ao3-mirror" LOGS_DIR="$BASE_DIR" PID_DIR="/dev/shm/ao3" WORKER_COUNT=2 START_PORT=8081 mkdir -p "$PID_DIR" # Kill any existing workers echo "[Startup] Killing existing workers..." for pid_file in "$PID_DIR"/worker-*.pid; do [ -f "$pid_file" ] && kill "$(cat "$pid_file")" 2>/dev/null || true done sleep 1 # Also kill by port for port in $(seq $START_PORT $((START_PORT + WORKER_COUNT - 1))); do fuser -k "${port}/tcp" 2>/dev/null || true done # Start backend workers echo "[Startup] Starting $WORKER_COUNT backend workers..." for i in $(seq 0 $((WORKER_COUNT - 1))); do port=$((START_PORT + i)) log_file="$LOGS_DIR/worker-$i.log" pid_file="$PID_DIR/worker-$i.pid" cd "$BASE_DIR" # Pin worker i to CPU i (2-core machine: CPU 0, CPU 1) taskset -c $i python3 -m uvicorn app:app \ --host 127.0.0.1 \ --port "$port" \ --workers 1 \ --loop uvloop \ --http httptools \ --log-level warning \ --timeout-keep-alive 30 \ >> "$log_file" 2>&1 & echo $! > "$pid_file" echo "[Startup] Worker $i started on port $port (PID: $!)" done # Wait for workers to be ready echo "[Startup] Waiting for workers to become healthy..." for i in $(seq 0 $((WORKER_COUNT - 1))); do port=$((START_PORT + i)) for attempt in $(seq 1 15); do if curl -sf "http://127.0.0.1:$port/health" > /dev/null 2>&1; then echo "[Startup] Worker $i (port $port) is healthy" break fi sleep 1 done done # Configure Caddy echo "[Startup] Applying Caddyfile..." sudo caddy fmt "$BASE_DIR/Caddyfile" --overwrite 2>/dev/null || true sudo cp "$BASE_DIR/Caddyfile" /etc/caddy/Caddyfile sudo systemctl reload caddy 2>/dev/null || sudo systemctl restart caddy echo "[Startup] Caddy reloaded" echo "[Startup] AO3 Mirror is running!" echo " Workers: 2 (ports 8081-8082, pinned to CPUs 0-1)" echo " Caddy: port 443 (agento3.miscs.dev)" echo " Stats: https://agento3.miscs.dev/stats" echo " Health: https://agento3.miscs.dev/health" echo " Logs: $LOGS_DIR/worker-*.log"