329 lines
7.9 KiB
Bash
329 lines
7.9 KiB
Bash
|
|
#!/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 "$@"
|