#!/bin/bash # 统一停止脚本 - 一键停止前后端应用(优化版) # 作者: Qwen Assistant # 功能: 安全停止前后端应用,清理进程和临时文件 set -e # 遇到错误立即退出 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 打印带颜色的消息 print_message() { local color=$1 local message=$2 echo -e "${color}${message}${NC}" } # 日志记录函数 log_message() { local level=$1 local message=$2 local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] [$level] $message" | tee -a "stop.log" } print_message $BLUE "🛑 开始停止 WordMaster Pro 系统..." # 记录停止过程 log_message "INFO" "开始停止 WordMaster Pro 系统" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # 检查是否有进程文件 has_process_files=false if [ -f ".backend.pid" ] || [ -f ".frontend.pid" ]; then has_process_files=true fi if [ "$has_process_files" = false ]; then print_message $YELLOW "⚠️ 未找到进程ID文件,系统可能未运行" log_message "WARNING" "未找到进程ID文件" # 尝试通过端口查找进程 if lsof -i :8888 > /dev/null 2>&1 || lsof -i :3000 > /dev/null 2>&1; then print_message $YELLOW "🔍 检测到可能的运行进程,尝试查找并停止..." BACKEND_PID=$(lsof -ti:8888 2>/dev/null) FRONTEND_PID=$(lsof -ti:3000 2>/dev/null) if [ ! -z "$BACKEND_PID" ]; then print_message $YELLOW "📡 发现后端进程 (PID: $BACKEND_PID),正在停止..." kill $BACKEND_PID 2>/dev/null || true sleep 1 if kill -0 $BACKEND_PID 2>/dev/null; then kill -9 $BACKEND_PID 2>/dev/null || true fi print_message $GREEN "✅ 后端进程已停止" fi if [ ! -z "$FRONTEND_PID" ]; then print_message $YELLOW "🎨 发现前端进程 (PID: $FRONTEND_PID),正在停止..." kill $FRONTEND_PID 2>/dev/null || true sleep 1 if kill -0 $FRONTEND_PID 2>/dev/null; then kill -9 $FRONTEND_PID 2>/dev/null || true fi print_message $GREEN "✅ 前端进程已停止" fi else print_message $GREEN "ℹ️ 系统未运行或已停止" log_message "INFO" "系统未运行或已停止" fi # 清理进程文件 rm -f .backend.pid .frontend.pid exit 0 fi # 停止后端 if [ -f ".backend.pid" ]; then BACKEND_PID=$(cat .backend.pid) if [ ! -z "$BACKEND_PID" ] && ps -p $BACKEND_PID > /dev/null 2>&1; then print_message $YELLOW "📡 正在停止后端服务 (PID: $BACKEND_PID)..." log_message "INFO" "停止后端服务 (PID: $BACKEND_PID)" # 发送SIGTERM信号,给进程优雅退出的机会 kill -TERM $BACKEND_PID 2>/dev/null || true sleep 3 # 检查进程是否仍然存在 if ps -p $BACKEND_PID > /dev/null 2>&1; then print_message $YELLOW "⏳ 后端进程仍在运行,等待更多时间..." sleep 5 # 再次检查 if ps -p $BACKEND_PID > /dev/null 2>&1; then print_message $YELLOW "⏳ 后端进程仍未退出,强制终止..." kill -9 $BACKEND_PID 2>/dev/null || true fi fi # 确认进程已终止 if ! ps -p $BACKEND_PID > /dev/null 2>&1; then print_message $GREEN "✅ 后端服务已停止" log_message "INFO" "后端服务已停止" else print_message $RED "❌ 无法停止后端进程 $BACKEND_PID" log_message "ERROR" "无法停止后端进程 $BACKEND_PID" fi else print_message $YELLOW "⚠️ 后端进程 $BACKEND_PID 不存在或已终止" log_message "WARNING" "后端进程 $BACKEND_PID 不存在" fi # 清理后端进程文件 rm -f .backend.pid else print_message $YELLOW "⚠️ 未找到后端进程ID文件" log_message "WARNING" "未找到后端进程ID文件" fi # 停止前端 if [ -f ".frontend.pid" ]; then FRONTEND_PID=$(cat .frontend.pid) if [ ! -z "$FRONTEND_PID" ] && ps -p $FRONTEND_PID > /dev/null 2>&1; then print_message $YELLOW "🎨 正在停止前端服务 (PID: $FRONTEND_PID)..." log_message "INFO" "停止前端服务 (PID: $FRONTEND_PID)" # 发送SIGTERM信号,给进程优雅退出的机会 kill -TERM $FRONTEND_PID 2>/dev/null || true sleep 2 # 检查进程是否仍然存在 if ps -p $FRONTEND_PID > /dev/null 2>&1; then print_message $YELLOW "⏳ 前端进程仍在运行,等待更多时间..." sleep 3 # 再次检查 if ps -p $FRONTEND_PID > /dev/null 2>&1; then print_message $YELLOW "⏳ 前端进程仍未退出,强制终止..." kill -9 $FRONTEND_PID 2>/dev/null || true fi fi # 确认进程已终止 if ! ps -p $FRONTEND_PID > /dev/null 2>&1; then print_message $GREEN "✅ 前端服务已停止" log_message "INFO" "前端服务已停止" else print_message $RED "❌ 无法停止前端进程 $FRONTEND_PID" log_message "ERROR" "无法停止前端进程 $FRONTEND_PID" fi else print_message $YELLOW "⚠️ 前端进程 $FRONTEND_PID 不存在或已终止" log_message "WARNING" "前端进程 $FRONTEND_PID 不存在" fi # 清理前端进程文件 rm -f .frontend.pid else print_message $YELLOW "⚠️ 未找到前端进程ID文件" log_message "WARNING" "未找到前端进程ID文件" fi # 额外清理:尝试停止任何可能的 uvicorn 或 vite 进程 print_message $BLUE "🧹 清理可能残留的进程..." ALL_UVICORN_PIDS=$(pgrep -f "uvicorn.*main:app" 2>/dev/null) ALL_VITE_PIDS=$(pgrep -f "vite" 2>/dev/null) if [ ! -z "$ALL_UVICORN_PIDS" ]; then print_message $YELLOW "🔍 发现可能的 uvicorn 进程: $ALL_UVICORN_PIDS" for pid in $ALL_UVICORN_PIDS; do if [ "$pid" != "$BACKEND_PID" ]; then # 避免重复停止 kill -TERM $pid 2>/dev/null || true sleep 1 if kill -0 $pid 2>/dev/null; then kill -9 $pid 2>/dev/null || true fi fi done print_message $GREEN "✅ uvicorn 进程已清理" fi if [ ! -z "$ALL_VITE_PIDS" ]; then print_message $YELLOW "🔍 发现可能的 vite 进程: $ALL_VITE_PIDS" for pid in $ALL_VITE_PIDS; do if [ "$pid" != "$FRONTEND_PID" ]; then # 避免重复停止 kill -TERM $pid 2>/dev/null || true sleep 1 if kill -0 $pid 2>/dev/null; then kill -9 $pid 2>/dev/null || true fi fi done print_message $GREEN "✅ vite 进程已清理" fi # 清理临时文件 print_message $BLUE "🧹 清理临时文件..." if [ -d "backend/__pycache__" ]; then rm -rf backend/__pycache__ 2>/dev/null || true fi if [ -d "backend/venv/lib/python*/__pycache__" ]; then rm -rf backend/venv/lib/python*/__pycache__ 2>/dev/null || true fi print_message $GREEN "✅ 临时文件已清理" # 显示清理完成信息 print_message $GREEN "" print_message $GREEN "🎉 WordMaster Pro 系统已完全停止!" print_message $GREEN "" print_message $BLUE "📋 清理完成项目:" print_message $GREEN "✅ 后端服务已停止" print_message $GREEN "✅ 前端服务已停止" print_message $GREEN "✅ 进程ID文件已清理" print_message $GREEN "✅ 可能的残留进程已清理" print_message $GREEN "✅ 临时文件已清理" echo "" print_message $BLUE "📁 日志记录: $(pwd)/stop.log" log_message "INFO" "WordMaster Pro 系统停止完成"