#!/bin/bash # 端口管理脚本 # 用于管理Flask应用的端口占用问题 # 配置 PORT=5002 APP_NAME="flask_prompt_master" PID_FILE="logs/gunicorn.pid" LOG_DIR="logs" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_debug() { echo -e "${BLUE}[DEBUG]${NC} $1" } # 检查端口是否被占用 check_port() { log_info "检查端口 $PORT 占用情况..." if ss -tlnp | grep -q ":$PORT "; then log_warn "端口 $PORT 已被占用" ss -tlnp | grep ":$PORT " return 1 else log_info "端口 $PORT 未被占用" return 0 fi } # 获取占用端口的进程 get_port_processes() { log_info "获取占用端口 $PORT 的进程信息..." local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u) if [ -n "$processes" ]; then log_warn "占用端口 $PORT 的进程:" for pid in $processes; do if ps -p $pid > /dev/null 2>&1; then ps -p $pid -o pid,ppid,cmd --no-headers fi done return 1 else log_info "没有进程占用端口 $PORT" return 0 fi } # 清理端口占用 clean_port() { log_info "清理端口 $PORT 占用..." local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u) if [ -n "$processes" ]; then log_warn "发现占用端口 $PORT 的进程,正在清理..." for pid in $processes; do if ps -p $pid > /dev/null 2>&1; then local cmd=$(ps -p $pid -o cmd --no-headers) log_info "终止进程 $pid: $cmd" kill -TERM $pid # 等待进程终止 local count=0 while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do sleep 1 count=$((count + 1)) done # 强制终止 if ps -p $pid > /dev/null 2>&1; then log_warn "强制终止进程 $pid" kill -KILL $pid fi fi done # 验证清理结果 sleep 2 if check_port; then log_info "端口 $PORT 清理成功" return 0 else log_error "端口 $PORT 清理失败" return 1 fi else log_info "端口 $PORT 未被占用,无需清理" return 0 fi } # 检查Gunicorn进程 check_gunicorn() { log_info "检查Gunicorn进程状态..." if [ -f "$PID_FILE" ]; then local pid=$(cat "$PID_FILE") if ps -p $pid > /dev/null 2>&1; then log_info "Gunicorn主进程 $pid 正在运行" local workers=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | wc -l) log_info "工作进程数量: $workers" return 0 else log_warn "PID文件存在但进程不存在: $pid" return 1 fi else log_warn "PID文件不存在: $PID_FILE" return 1 fi } # 启动应用 start_app() { log_info "启动Flask应用..." # 切换到项目目录 cd "$PROJECT_DIR" || { log_error "无法切换到项目目录: $PROJECT_DIR" return 1 } # 激活conda环境 if command -v conda > /dev/null 2>&1; then log_info "激活conda环境..." eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv fi # 检查端口 if ! check_port; then log_warn "端口被占用,尝试清理..." if ! clean_port; then log_error "无法清理端口占用,启动失败" return 1 fi fi # 启动Gunicorn log_info "启动Gunicorn服务..." nohup gunicorn -c gunicorn.conf.py run_dev:app > "$LOG_DIR/gunicorn_startup.log" 2>&1 & # 等待启动 sleep 5 # 验证启动 if check_gunicorn; then log_info "应用启动成功" return 0 else log_error "应用启动失败" return 1 fi } # 停止应用 stop_app() { log_info "停止Flask应用..." if [ -f "$PID_FILE" ]; then local pid=$(cat "$PID_FILE") if ps -p $pid > /dev/null 2>&1; then log_info "停止Gunicorn主进程 $pid" kill -TERM $pid # 等待进程终止 local count=0 while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do sleep 1 count=$((count + 1)) done # 强制终止 if ps -p $pid > /dev/null 2>&1; then log_warn "强制终止进程 $pid" kill -KILL $pid fi fi fi # 清理所有相关进程 local gunicorn_pids=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | awk '{print $2}') if [ -n "$gunicorn_pids" ]; then log_info "清理Gunicorn工作进程..." for pid in $gunicorn_pids; do kill -TERM $pid 2>/dev/null done fi log_info "应用停止完成" } # 重启应用 restart_app() { log_info "重启Flask应用..." stop_app sleep 2 start_app } # 状态检查 status() { log_info "=== Flask应用状态检查 ===" echo "1. 端口占用检查:" if check_port; then echo " ✅ 端口 $PORT 可用" else echo " ❌ 端口 $PORT 被占用" get_port_processes fi echo "" echo "2. Gunicorn进程检查:" if check_gunicorn; then echo " ✅ Gunicorn正在运行" else echo " ❌ Gunicorn未运行" fi echo "" echo "3. 服务响应检查:" if curl -s http://localhost:$PORT/ > /dev/null 2>&1; then echo " ✅ 服务正常响应" else echo " ❌ 服务无响应" fi } # 监控模式 monitor() { log_info "启动端口监控模式..." while true; do if ! check_gunicorn; then log_warn "检测到Gunicorn进程异常,尝试重启..." restart_app fi if ! curl -s http://localhost:$PORT/ > /dev/null 2>&1; then log_warn "检测到服务无响应,尝试重启..." restart_app fi sleep 30 done } # 帮助信息 show_help() { echo "端口管理脚本使用方法:" echo "" echo " $0 check - 检查端口占用情况" echo " $0 clean - 清理端口占用" echo " $0 start - 启动应用" echo " $0 stop - 停止应用" echo " $0 restart - 重启应用" echo " $0 status - 查看应用状态" echo " $0 monitor - 启动监控模式" echo " $0 help - 显示帮助信息" echo "" echo "示例:" echo " $0 status # 检查当前状态" echo " $0 restart # 重启应用" echo " $0 monitor # 后台监控" } # 主函数 main() { case "${1:-help}" in check) check_port ;; clean) clean_port ;; start) start_app ;; stop) stop_app ;; restart) restart_app ;; status) status ;; monitor) monitor ;; help|--help|-h) show_help ;; *) log_error "未知命令: $1" show_help exit 1 ;; esac } # 执行主函数 main "$@"