feat: implement graceful shutdown with SIGINT/SIGTERM support
- Add WebSocket shutdown() with client notification and graceful close - Enhance download service stop() with pending state persistence - Expand FastAPI lifespan shutdown with proper cleanup sequence - Add SQLite WAL checkpoint before database close - Update stop_server.sh to use SIGTERM with timeout fallback - Configure uvicorn timeout_graceful_shutdown=30s - Update ARCHITECTURE.md with shutdown documentation
This commit is contained in:
@@ -1,22 +1,93 @@
|
||||
#!/bin/bash
|
||||
# Stop Aniworld FastAPI Server
|
||||
# Stop Aniworld FastAPI Server (Graceful Shutdown)
|
||||
#
|
||||
# This script performs a graceful shutdown by sending SIGTERM first,
|
||||
# allowing the application to clean up resources properly before
|
||||
# falling back to SIGKILL if needed.
|
||||
|
||||
echo "Stopping Aniworld server..."
|
||||
GRACEFUL_TIMEOUT=30 # seconds to wait for graceful shutdown
|
||||
|
||||
# Method 1: Kill uvicorn processes
|
||||
pkill -f "uvicorn.*fastapi_app:app" && echo "✓ Stopped uvicorn processes"
|
||||
echo "Stopping Aniworld server (graceful shutdown)..."
|
||||
|
||||
# Method 2: Kill any process using port 8000
|
||||
# Function to wait for a process to terminate
|
||||
wait_for_process() {
|
||||
local pid=$1
|
||||
local timeout=$2
|
||||
local count=0
|
||||
|
||||
while [ $count -lt $timeout ]; do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
return 0 # Process terminated
|
||||
fi
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
echo -ne "\r Waiting for graceful shutdown... ${count}/${timeout}s"
|
||||
done
|
||||
echo ""
|
||||
return 1 # Timeout
|
||||
}
|
||||
|
||||
# Method 1: Gracefully stop uvicorn processes
|
||||
UVICORN_PIDS=$(pgrep -f "uvicorn.*fastapi_app:app")
|
||||
if [ -n "$UVICORN_PIDS" ]; then
|
||||
echo "Sending SIGTERM to uvicorn processes..."
|
||||
for pid in $UVICORN_PIDS; do
|
||||
kill -TERM "$pid" 2>/dev/null
|
||||
done
|
||||
|
||||
# Wait for graceful shutdown
|
||||
all_terminated=true
|
||||
for pid in $UVICORN_PIDS; do
|
||||
if ! wait_for_process "$pid" "$GRACEFUL_TIMEOUT"; then
|
||||
all_terminated=false
|
||||
echo " Process $pid did not terminate gracefully, forcing..."
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
if $all_terminated; then
|
||||
echo "✓ Uvicorn processes stopped gracefully"
|
||||
else
|
||||
echo "✓ Uvicorn processes stopped (forced)"
|
||||
fi
|
||||
else
|
||||
echo "✓ No uvicorn processes running"
|
||||
fi
|
||||
|
||||
# Method 2: Gracefully stop any process using port 8000
|
||||
PORT_PID=$(lsof -ti:8000)
|
||||
if [ -n "$PORT_PID" ]; then
|
||||
kill -9 $PORT_PID
|
||||
echo "✓ Killed process on port 8000 (PID: $PORT_PID)"
|
||||
echo "Found process on port 8000 (PID: $PORT_PID)"
|
||||
|
||||
# Send SIGTERM first
|
||||
kill -TERM "$PORT_PID" 2>/dev/null
|
||||
|
||||
if wait_for_process "$PORT_PID" "$GRACEFUL_TIMEOUT"; then
|
||||
echo "✓ Process on port 8000 stopped gracefully"
|
||||
else
|
||||
echo " Graceful shutdown timed out, forcing..."
|
||||
kill -9 "$PORT_PID" 2>/dev/null
|
||||
echo "✓ Process on port 8000 stopped (forced)"
|
||||
fi
|
||||
else
|
||||
echo "✓ Port 8000 is already free"
|
||||
fi
|
||||
|
||||
# Method 3: Kill any python processes running the server
|
||||
pkill -f "run_server.py" && echo "✓ Stopped run_server.py processes"
|
||||
# Method 3: Gracefully stop run_server.py processes
|
||||
SERVER_PIDS=$(pgrep -f "run_server.py")
|
||||
if [ -n "$SERVER_PIDS" ]; then
|
||||
echo "Sending SIGTERM to run_server.py processes..."
|
||||
for pid in $SERVER_PIDS; do
|
||||
kill -TERM "$pid" 2>/dev/null
|
||||
done
|
||||
|
||||
for pid in $SERVER_PIDS; do
|
||||
if ! wait_for_process "$pid" 10; then
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
fi
|
||||
done
|
||||
echo "✓ Stopped run_server.py processes"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Server stopped successfully!"
|
||||
|
||||
Reference in New Issue
Block a user