Files
QueryRewrite/manage_services.sh
T
2025-09-01 17:34:19 +08:00

270 lines
6.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# 统一管理脚本:启动/停止/查看 四个 API 服务
# 支持服务:
# - intent -> rag2_0.api.intent_recognition_api:app (port 8001, workers 25)
# - dify -> rag2_0.api.DifyQueryRetrieval_api:app (port 8002, workers 25)
# - answertype -> rag2_0.api.AnswerType_api:app (port 8003, workers 1)
# - qingdan -> rag2_0.api.query_dinge_qingdan_api:app (port 8005, workers 1)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 定义服务配置:会话名 与 启动命令
SERVICE_NAMES=(intent dify answertype qingdan)
service_port() {
case "$1" in
intent) echo "8001" ;;
dify) echo "8002" ;;
answertype) echo "8003" ;;
qingdan) echo "8005" ;;
*) echo "" ;;
esac
}
session_name() {
case "$1" in
intent) echo "intent_recognition_api" ;;
dify) echo "DifyQueryRetrieval_api" ;;
answertype) echo "AnswerType" ;;
qingdan) echo "query_dinge_qingdan_api" ;;
*) echo "" ;;
esac
}
start_command() {
case "$1" in
intent)
echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.intent_recognition_api:app --host 0.0.0.0 --port 8001 --workers 4" ;;
dify)
echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.DifyQueryRetrieval_api:app --host 0.0.0.0 --port 8002 --workers 4" ;;
answertype)
echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.AnswerType_api:app --host 0.0.0.0 --port 8003 --workers 1" ;;
qingdan)
echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.query_dinge_qingdan_api:app --host 0.0.0.0 --port 8005 --workers 4" ;;
*) echo "" ;;
esac
}
exists_session() {
# 使用严格匹配,避免误判
local name="$1"
if screen -ls 2>/dev/null | grep -q "\\.${name}\\s"; then
return 0
fi
return 1
}
# 按端口获取监听该端口的任意一个PID,优先用 ss,其次 lsof
pids_on_port() {
local port="$1"
# 从 ss 提取 pid 列表
local ss_pids
ss_pids=$(ss -lptn 2>/dev/null \
| grep -E ":${port}\\b" \
| awk '{print $NF}' \
| sed -n 's/.*pid=\([0-9]\+\),.*/\1/p' \
| sort -u)
if [[ -n "$ss_pids" ]]; then
echo "$ss_pids"
return 0
fi
# 从 lsof 提取 pid 列表
if command -v lsof >/dev/null 2>&1; then
local lsof_pids
lsof_pids=$(lsof -nP -i :"$port" -sTCP:LISTEN -t 2>/dev/null | sort -u)
if [[ -n "$lsof_pids" ]]; then
echo "$lsof_pids"
return 0
fi
fi
return 1
}
# 根据端口优雅终止(TERM)并在必要时强制(KILL)清理进程
kill_by_port() {
local port="$1"
local pids
pids=$(pids_on_port "$port" || true)
if [[ -z "$pids" ]]; then
return 0
fi
echo "[清理] 端口 $port 仍被占用,发送 SIGTERM 到: $pids"
kill -TERM $pids 2>/dev/null || true
sleep 2
# 再次检查
local left
left=$(pids_on_port "$port" || true)
if [[ -n "$left" ]]; then
echo "[强制] 端口 $port 仍占用,发送 SIGKILL 到: $left"
kill -KILL $left 2>/dev/null || true
fi
}
start_service() {
local svc="$1"
local sname
sname="$(session_name "$svc")"
if [[ -z "$sname" ]]; then echo "未知服务: $svc"; return 2; fi
if exists_session "$sname"; then
echo "[跳过] 会话 '$sname' 已存在"
return 0
fi
local cmd
cmd="$(start_command "$svc")"
if [[ -z "$cmd" ]]; then echo "未配置启动命令: $svc"; return 2; fi
screen -dmS "$sname" bash -c "$cmd"
echo "[启动] $svc -> screen 会话 '$sname'"
}
stop_service() {
local svc="$1"
local sname
sname="$(session_name "$svc")"
local port
port="$(service_port "$svc")"
if [[ -z "$sname" || -z "$port" ]]; then echo "未知服务: $svc"; return 2; fi
# 1) 先尝试关闭 screen 会话
if exists_session "$sname"; then
screen -S "$sname" -X quit || true
echo "[停止] $svc -> '$sname'"
else
echo "[提示] 未发现 screen 会话: $sname"
fi
# 2) 等待释放端口
sleep 2
# 3) 如果仍占用,按端口清理
if ss -lptn 2>/dev/null | grep -E -q ":${port}\\b" || (command -v lsof >/dev/null 2>&1 && lsof -i :"$port" -sTCP:LISTEN >/dev/null 2>&1); then
kill_by_port "$port"
fi
}
status_service() {
local svc="$1"
local sname
sname="$(session_name "$svc")"
if [[ -z "$sname" ]]; then echo "未知服务: $svc"; return 2; fi
if exists_session "$sname"; then
echo "[运行中] $svc -> '$sname'"
else
echo "[未运行] $svc"
fi
}
attach_service() {
local svc="$1"
local sname
sname="$(session_name "$svc")"
if [[ -z "$sname" ]]; then echo "未知服务: $svc"; return 2; fi
if exists_session "$sname"; then
echo "附着到会话: $sname (退出: Ctrl+A 然后 D)"
screen -r "$sname"
else
echo "服务未运行: $svc"
return 1
fi
}
start_all() {
for s in "${SERVICE_NAMES[@]}"; do
start_service "$s"
done
}
stop_all() {
for s in "${SERVICE_NAMES[@]}"; do
stop_service "$s"
done
}
status_all() {
for s in "${SERVICE_NAMES[@]}"; do
status_service "$s"
done
}
restart_service() {
local svc="$1"
stop_service "$svc"
# 等待会话释放
sleep 1
start_service "$svc"
}
usage() {
cat <<EOF
用法: $0 <command> [service]
command:
start [svc] 启动指定服务;不指定时启动全部
stop [svc] 停止指定服务;不指定时停止全部
restart [svc] 重启指定服务;不指定时重启全部
status 查看所有服务状态
attach <svc> 附着到指定服务的 screen 会话
force-stop [svc] 强制结束进程(按端口终止);不指定时对全部执行
service 可选值:
intent | dify | answertype | qingdan
EOF
}
main() {
local cmd="${1:-}"; shift || true
case "$cmd" in
start)
local svc="${1:-all}"
if [[ "$svc" == "all" ]]; then start_all; else start_service "$svc"; fi
;;
stop)
local svc="${1:-all}"
if [[ "$svc" == "all" ]]; then stop_all; else stop_service "$svc"; fi
;;
restart)
local svc="${1:-all}"
if [[ "$svc" == "all" ]]; then
for s in "${SERVICE_NAMES[@]}"; do restart_service "$s"; done
else
restart_service "$svc"
fi
;;
status)
status_all
;;
attach)
local svc="${1:-}"
if [[ -z "$svc" ]]; then echo "请指定服务"; usage; exit 2; fi
attach_service "$svc"
;;
force-stop)
local svc="${1:-all}"
if [[ "$svc" == "all" ]]; then
for s in "${SERVICE_NAMES[@]}"; do
# 仅按端口强制清理
p="$(service_port "$s")"
if [[ -n "$p" ]]; then kill_by_port "$p"; fi
done
else
local p
p="$(service_port "$svc")"
if [[ -z "$p" ]]; then echo "未知服务: $svc"; exit 2; fi
kill_by_port "$p"
fi
;;
""|-h|--help|help)
usage
;;
*)
echo "未知命令: $cmd" >&2
usage
exit 2
;;
esac
}
main "$@"