Files
aitsc/scripts/port_manager.sh

329 lines
7.9 KiB
Bash
Raw Permalink Normal View History

#!/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 "$@"