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