Service Scripts: - start-services.sh: Add pre-flight checks, health monitoring, --dev/--prod modes, port options, dependency checks, and version logging - stop-services.sh: Add port 3000 cleanup, verification, --quiet/--force flags - status-services.sh: New script for monitoring service status with --watch mode WebSocket: - Remove conflicting socket.client.ts plugin that was interfering with useWebSocket.ts composable (used JWT auth vs cookie auth) - Add debugging logs to useWebSocket.ts to diagnose intermittent connection issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
278 lines
7.7 KiB
Bash
Executable File
278 lines
7.7 KiB
Bash
Executable File
#!/bin/bash
|
||
# Stop both backend and frontend services
|
||
# Enhanced to kill entire process trees, clean up orphans, and verify shutdown
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
LOG_DIR="$SCRIPT_DIR/logs"
|
||
BACKEND_PORT=8000
|
||
FRONTEND_PORT=3000
|
||
|
||
# Parse arguments
|
||
QUIET_MODE=false
|
||
FORCE_MODE=false
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
--quiet|-q)
|
||
QUIET_MODE=true
|
||
shift
|
||
;;
|
||
--force|-f)
|
||
FORCE_MODE=true
|
||
shift
|
||
;;
|
||
--help|-h)
|
||
echo "Usage: $0 [OPTIONS]"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --quiet, -q Minimal output"
|
||
echo " --force, -f Skip graceful shutdown, kill immediately"
|
||
echo " --help, -h Show this help message"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo "Unknown option: $1"
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
log() {
|
||
if [ "$QUIET_MODE" = false ]; then
|
||
echo "$@"
|
||
fi
|
||
}
|
||
|
||
log "========================================"
|
||
log "🛑 Stopping SBA Gameplay Services"
|
||
log "========================================"
|
||
log ""
|
||
|
||
# Function to kill process tree
|
||
kill_tree() {
|
||
local pid=$1
|
||
local sig=${2:-TERM}
|
||
|
||
# Get all child PIDs
|
||
local children=$(pgrep -P "$pid" 2>/dev/null || true)
|
||
|
||
# Kill children first (depth-first)
|
||
for child in $children; do
|
||
kill_tree "$child" "$sig"
|
||
done
|
||
|
||
# Kill the parent
|
||
if ps -p "$pid" > /dev/null 2>&1; then
|
||
kill -"$sig" "$pid" 2>/dev/null || true
|
||
fi
|
||
}
|
||
|
||
# Function to stop a service gracefully
|
||
stop_service() {
|
||
local name=$1
|
||
local pid_file=$2
|
||
local icon=$3
|
||
|
||
if [ -f "$pid_file" ]; then
|
||
local pid=$(cat "$pid_file")
|
||
if ps -p "$pid" > /dev/null 2>&1; then
|
||
log "$icon Stopping $name (PID: $pid)..."
|
||
|
||
if [ "$FORCE_MODE" = true ]; then
|
||
# Force mode: kill immediately
|
||
kill_tree "$pid" KILL
|
||
log " ✓ $name killed (force mode)"
|
||
else
|
||
# Graceful mode: SIGTERM first, then SIGKILL
|
||
kill_tree "$pid" TERM
|
||
|
||
# Wait up to 5 seconds for graceful shutdown
|
||
local wait_count=0
|
||
while [ $wait_count -lt 5 ]; do
|
||
if ! ps -p "$pid" > /dev/null 2>&1; then
|
||
break
|
||
fi
|
||
sleep 1
|
||
wait_count=$((wait_count + 1))
|
||
done
|
||
|
||
# Force kill if still running
|
||
if ps -p "$pid" > /dev/null 2>&1; then
|
||
log " → Graceful shutdown timed out, forcing..."
|
||
kill_tree "$pid" KILL
|
||
sleep 1
|
||
fi
|
||
|
||
if ps -p "$pid" > /dev/null 2>&1; then
|
||
log " ⚠️ $name may still be running"
|
||
else
|
||
log " ✓ $name stopped"
|
||
fi
|
||
fi
|
||
else
|
||
log " ⚠️ $name process not found (stale PID file)"
|
||
fi
|
||
rm -f "$pid_file"
|
||
else
|
||
log " ℹ️ No $name PID file found"
|
||
fi
|
||
}
|
||
|
||
# Stop Backend
|
||
stop_service "Backend" "$LOG_DIR/backend.pid" "📡"
|
||
log ""
|
||
|
||
# Stop Frontend
|
||
stop_service "Frontend" "$LOG_DIR/frontend.pid" "🎨"
|
||
log ""
|
||
|
||
# ============================================
|
||
# AGGRESSIVE CLEANUP: Kill orphaned processes
|
||
# ============================================
|
||
log "🔍 Checking for orphaned processes..."
|
||
|
||
ORPHANS_FOUND=false
|
||
|
||
# Kill all backend processes for this specific app
|
||
# Use more specific pattern to avoid killing unrelated processes
|
||
BACKEND_PATTERN="python.*app\.main"
|
||
BACKEND_PIDS=$(pgrep -f "$BACKEND_PATTERN" 2>/dev/null || true)
|
||
|
||
# Also check for uvicorn processes
|
||
UVICORN_PATTERN="uvicorn.*app\.main"
|
||
UVICORN_PIDS=$(pgrep -f "$UVICORN_PATTERN" 2>/dev/null || true)
|
||
|
||
# Combine and deduplicate
|
||
ALL_BACKEND_PIDS=$(echo "$BACKEND_PIDS $UVICORN_PIDS" | tr ' ' '\n' | sort -u | tr '\n' ' ' | xargs)
|
||
|
||
if [ -n "$ALL_BACKEND_PIDS" ]; then
|
||
ORPHANS_FOUND=true
|
||
log " Found orphaned backend processes: $ALL_BACKEND_PIDS"
|
||
for pid in $ALL_BACKEND_PIDS; do
|
||
kill_tree "$pid" KILL
|
||
done
|
||
log " ✓ Killed orphaned backend processes"
|
||
fi
|
||
|
||
# Kill processes on backend port
|
||
PORT_BACKEND_PIDS=$(lsof -ti :$BACKEND_PORT 2>/dev/null || true)
|
||
if [ -n "$PORT_BACKEND_PIDS" ]; then
|
||
ORPHANS_FOUND=true
|
||
log " Found processes on port $BACKEND_PORT: $PORT_BACKEND_PIDS"
|
||
for pid in $PORT_BACKEND_PIDS; do
|
||
kill -9 "$pid" 2>/dev/null || true
|
||
done
|
||
log " ✓ Killed processes on port $BACKEND_PORT"
|
||
fi
|
||
|
||
# Kill processes on frontend port
|
||
PORT_FRONTEND_PIDS=$(lsof -ti :$FRONTEND_PORT 2>/dev/null || true)
|
||
if [ -n "$PORT_FRONTEND_PIDS" ]; then
|
||
ORPHANS_FOUND=true
|
||
log " Found processes on port $FRONTEND_PORT: $PORT_FRONTEND_PIDS"
|
||
for pid in $PORT_FRONTEND_PIDS; do
|
||
kill -9 "$pid" 2>/dev/null || true
|
||
done
|
||
log " ✓ Killed processes on port $FRONTEND_PORT"
|
||
fi
|
||
|
||
# Kill nuxt dev processes specifically for this project
|
||
# Check if process command line contains our project path
|
||
NUXT_PIDS=""
|
||
for pid in $(pgrep -f "nuxt.*dev" 2>/dev/null || true); do
|
||
# Verify this is for our project by checking cwd or command
|
||
if ps -p "$pid" -o args= 2>/dev/null | grep -q "$SCRIPT_DIR" 2>/dev/null; then
|
||
NUXT_PIDS="$NUXT_PIDS $pid"
|
||
fi
|
||
done
|
||
NUXT_PIDS=$(echo "$NUXT_PIDS" | xargs)
|
||
|
||
if [ -n "$NUXT_PIDS" ]; then
|
||
ORPHANS_FOUND=true
|
||
log " Found orphaned frontend processes: $NUXT_PIDS"
|
||
for pid in $NUXT_PIDS; do
|
||
kill_tree "$pid" KILL
|
||
done
|
||
log " ✓ Killed orphaned frontend processes"
|
||
fi
|
||
|
||
# Kill any node processes that might be related to our frontend
|
||
# Be more conservative here - only kill if definitely ours
|
||
NODE_PIDS=""
|
||
for pid in $(pgrep -f "node.*$SCRIPT_DIR/frontend" 2>/dev/null || true); do
|
||
NODE_PIDS="$NODE_PIDS $pid"
|
||
done
|
||
NODE_PIDS=$(echo "$NODE_PIDS" | xargs)
|
||
|
||
if [ -n "$NODE_PIDS" ]; then
|
||
ORPHANS_FOUND=true
|
||
log " Found orphaned node processes: $NODE_PIDS"
|
||
for pid in $NODE_PIDS; do
|
||
kill -9 "$pid" 2>/dev/null || true
|
||
done
|
||
log " ✓ Killed orphaned node processes"
|
||
fi
|
||
|
||
if [ "$ORPHANS_FOUND" = false ]; then
|
||
log " ✓ No orphaned processes found"
|
||
fi
|
||
|
||
log ""
|
||
|
||
# ============================================
|
||
# VERIFICATION: Confirm services are stopped
|
||
# ============================================
|
||
log "🔍 Verification..."
|
||
|
||
# Give processes a moment to fully release ports
|
||
sleep 1
|
||
|
||
VERIFICATION_OK=true
|
||
|
||
# Check backend port
|
||
if lsof -ti :$BACKEND_PORT > /dev/null 2>&1; then
|
||
log " ⚠️ Port $BACKEND_PORT still in use!"
|
||
VERIFICATION_OK=false
|
||
else
|
||
log " ✓ Port $BACKEND_PORT is free"
|
||
fi
|
||
|
||
# Check frontend port
|
||
if lsof -ti :$FRONTEND_PORT > /dev/null 2>&1; then
|
||
log " ⚠️ Port $FRONTEND_PORT still in use!"
|
||
VERIFICATION_OK=false
|
||
else
|
||
log " ✓ Port $FRONTEND_PORT is free"
|
||
fi
|
||
|
||
# Check for any remaining processes
|
||
REMAINING_BACKEND=$(pgrep -f "$BACKEND_PATTERN" 2>/dev/null || true)
|
||
if [ -n "$REMAINING_BACKEND" ]; then
|
||
log " ⚠️ Backend processes still running: $REMAINING_BACKEND"
|
||
VERIFICATION_OK=false
|
||
fi
|
||
|
||
log ""
|
||
|
||
# ============================================
|
||
# SUMMARY
|
||
# ============================================
|
||
if [ "$VERIFICATION_OK" = true ]; then
|
||
log "========================================"
|
||
log "✅ Services Stopped Successfully!"
|
||
log "========================================"
|
||
else
|
||
log "========================================"
|
||
log "⚠️ Services Stopped (with warnings)"
|
||
log "========================================"
|
||
log ""
|
||
log "Some processes may still be running. Try:"
|
||
log " $0 --force"
|
||
log ""
|
||
log "Or manually check:"
|
||
log " lsof -ti :$BACKEND_PORT"
|
||
log " lsof -ti :$FRONTEND_PORT"
|
||
fi
|
||
|
||
log ""
|