feat: add Linux deployment scripts (deploy/start/stop/run_eval)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
173
deploy.sh
Normal file
173
deploy.sh
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# deploy.sh — Siemens RAGAS 一键部署脚本(Linux)
|
||||||
|
# 用法:bash deploy.sh
|
||||||
|
# 功能:检查环境 → 安装依赖 → 初始化配置 → 启动后台服务
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# ── 颜色输出 ──────────────────────────────────────────────────────
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
else
|
||||||
|
GREEN=''; YELLOW=''; RED=''; CYAN=''; NC=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo -e "${CYAN} Siemens RAGAS Console — Linux 一键部署${NC}"
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ── 阶段 1:Python 版本检查 ───────────────────────────────────────
|
||||||
|
info "阶段 1/7:检查 Python 版本..."
|
||||||
|
|
||||||
|
PYTHON_BIN=""
|
||||||
|
for candidate in python3.12 python3.13 python3.14 python3; do
|
||||||
|
if command -v "$candidate" &>/dev/null; then
|
||||||
|
version=$("$candidate" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>/dev/null || true)
|
||||||
|
major=$(echo "$version" | cut -d. -f1)
|
||||||
|
minor=$(echo "$version" | cut -d. -f2)
|
||||||
|
if [ "${major:-0}" -ge 3 ] && [ "${minor:-0}" -ge 12 ]; then
|
||||||
|
PYTHON_BIN="$candidate"
|
||||||
|
ok "Python $version ($candidate)"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$PYTHON_BIN" ]; then
|
||||||
|
err "未找到 Python 3.12+。请安装后重试。"
|
||||||
|
err " Ubuntu/Debian: sudo apt install python3.12 python3.12-venv"
|
||||||
|
err " CentOS/RHEL: sudo dnf install python3.12"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 阶段 2:虚拟环境 ──────────────────────────────────────────────
|
||||||
|
info "阶段 2/7:准备虚拟环境..."
|
||||||
|
|
||||||
|
if [ -d ".venv" ] && [ -f ".venv/bin/python" ]; then
|
||||||
|
ok ".venv 已存在,跳过创建"
|
||||||
|
else
|
||||||
|
info "创建 .venv..."
|
||||||
|
"$PYTHON_BIN" -m venv .venv
|
||||||
|
ok ".venv 创建完成"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PIP=".venv/bin/pip"
|
||||||
|
PYTHON=".venv/bin/python"
|
||||||
|
|
||||||
|
# ── 阶段 3:安装依赖 ──────────────────────────────────────────────
|
||||||
|
info "阶段 3/7:安装项目依赖(可能需要几分钟)..."
|
||||||
|
|
||||||
|
"$PIP" install --upgrade pip -q
|
||||||
|
ok "pip 已升级"
|
||||||
|
|
||||||
|
"$PIP" install -e . -q
|
||||||
|
ok "项目依赖安装完成(pyproject.toml)"
|
||||||
|
|
||||||
|
"$PIP" install fastapi uvicorn httpx -q
|
||||||
|
ok "Web 服务依赖安装完成(fastapi / uvicorn / httpx)"
|
||||||
|
|
||||||
|
# ── 阶段 4:配置文件 ──────────────────────────────────────────────
|
||||||
|
info "阶段 4/7:初始化配置文件..."
|
||||||
|
|
||||||
|
if [ ! -f ".env" ]; then
|
||||||
|
cp .env.example .env
|
||||||
|
warn ".env 已从 .env.example 复制,请编辑填写实际的 API Key 等配置后再启动:"
|
||||||
|
warn " nano .env 或 vim .env"
|
||||||
|
warn " 关键字段:OPENAI_API_KEY, OPENAI_BASE_URL, ALIBABA_ACCESS_KEY_ID, ALIBABA_ACCESS_KEY_SECRET"
|
||||||
|
else
|
||||||
|
ok ".env 已存在,跳过"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 阶段 5:目录初始化 ────────────────────────────────────────────
|
||||||
|
info "阶段 5/7:初始化目录结构..."
|
||||||
|
|
||||||
|
mkdir -p configs logs outputs datasets
|
||||||
|
ok "目录就绪:configs/ logs/ outputs/ datasets/"
|
||||||
|
|
||||||
|
# 确保其他脚本有执行权限
|
||||||
|
for script in start.sh stop.sh run_eval.sh; do
|
||||||
|
[ -f "$script" ] && chmod +x "$script"
|
||||||
|
done
|
||||||
|
ok "辅助脚本已设置执行权限"
|
||||||
|
|
||||||
|
# ── 阶段 6:Demo 数据 ─────────────────────────────────────────────
|
||||||
|
info "阶段 6/7:初始化演示数据..."
|
||||||
|
|
||||||
|
DEMO_DIR="outputs/kba-knowledge-base-offline-baseline"
|
||||||
|
if [ -d "$DEMO_DIR" ]; then
|
||||||
|
ok "演示数据已存在,跳过"
|
||||||
|
else
|
||||||
|
info "生成演示数据(scripts/seed_sample_run.py)..."
|
||||||
|
if "$PYTHON" scripts/seed_sample_run.py; then
|
||||||
|
ok "演示数据生成完成"
|
||||||
|
else
|
||||||
|
warn "演示数据生成失败,控制台报告页将为空(服务仍可正常启动)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 阶段 7:启动服务 ──────────────────────────────────────────────
|
||||||
|
info "阶段 7/7:启动 Web 服务..."
|
||||||
|
|
||||||
|
# 检查 .env 是否包含默认占位符
|
||||||
|
if grep -q "your-api-key" .env 2>/dev/null; then
|
||||||
|
warn ".env 中仍包含默认占位符,部分功能(评估执行)将不可用"
|
||||||
|
warn "请编辑 .env 后重新运行 start.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 端口检测
|
||||||
|
PORT=8800
|
||||||
|
if ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||||
|
warn "端口 $PORT 已被占用,尝试 8801..."
|
||||||
|
PORT=8801
|
||||||
|
if ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||||
|
err "端口 8800 和 8801 均被占用。请手动运行:"
|
||||||
|
err " .venv/bin/python webmain.py --host 0.0.0.0 --port <PORT>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 清理残留 PID
|
||||||
|
if [ -f ".server.pid" ]; then
|
||||||
|
OLD_PID=$(cat .server.pid)
|
||||||
|
if kill -0 "$OLD_PID" 2>/dev/null; then
|
||||||
|
warn "检测到已有服务进程 (PID=$OLD_PID),停止旧进程..."
|
||||||
|
kill "$OLD_PID" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
rm -f .server.pid
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 后台启动
|
||||||
|
nohup "$PYTHON" webmain.py --host 0.0.0.0 --port "$PORT" >> logs/server.log 2>&1 &
|
||||||
|
SERVER_PID=$!
|
||||||
|
echo "$SERVER_PID" > .server.pid
|
||||||
|
|
||||||
|
# 等待 3 秒验证进程存活
|
||||||
|
sleep 3
|
||||||
|
if kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||||
|
ok "服务已启动 (PID=$SERVER_PID)"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo -e "${GREEN} 部署成功!${NC}"
|
||||||
|
echo -e "${GREEN} 访问地址: http://$(hostname -I | awk '{print $1}'):${PORT}${NC}"
|
||||||
|
echo -e "${GREEN} 本机访问: http://127.0.0.1:${PORT}${NC}"
|
||||||
|
echo -e "${CYAN} 服务日志: tail -f logs/server.log${NC}"
|
||||||
|
echo -e "${CYAN} 停止服务: bash stop.sh${NC}"
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
err "服务启动失败,请查看日志:"
|
||||||
|
err " tail -20 logs/server.log"
|
||||||
|
rm -f .server.pid
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
147
run_eval.sh
Normal file
147
run_eval.sh
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# run_eval.sh — Siemens RAGAS 评估运行脚本(Linux)
|
||||||
|
# 对应 Windows 的 run_eval.ps1
|
||||||
|
#
|
||||||
|
# 用法:
|
||||||
|
# bash run_eval.sh # online 评估(默认)
|
||||||
|
# bash run_eval.sh offline # offline 冒烟测试
|
||||||
|
# bash run_eval.sh scenarios/xxx.yaml # 自定义场景
|
||||||
|
# bash run_eval.sh online DEBUG # 指定日志级别
|
||||||
|
# bash run_eval.sh build scenarios/siemens_build/siemens-pdf-build.yaml
|
||||||
|
# # 题库生成
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# ── 颜色输出 ──────────────────────────────────────────────────────
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
else
|
||||||
|
GREEN=''; YELLOW=''; RED=''; CYAN=''; NC=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
|
||||||
|
|
||||||
|
# ── 参数解析 ──────────────────────────────────────────────────────
|
||||||
|
SCENARIO="${1:-online}"
|
||||||
|
LOG_LEVEL="${2:-INFO}"
|
||||||
|
|
||||||
|
# 场景别名映射
|
||||||
|
declare -A SCENARIO_MAP=(
|
||||||
|
["online"]="scenarios/online/siemens-pdf-question-bank-online.yaml"
|
||||||
|
["offline"]="scenarios/offline/siemens-pdf-offline-smoke.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 检测是否是 dataset build 模式
|
||||||
|
BUILD_MODE=false
|
||||||
|
BUILD_CONFIG=""
|
||||||
|
if [ "$SCENARIO" = "build" ]; then
|
||||||
|
BUILD_MODE=true
|
||||||
|
BUILD_CONFIG="${2:-scenarios/siemens_build/siemens-pdf-build.yaml}"
|
||||||
|
LOG_LEVEL="${3:-INFO}"
|
||||||
|
elif [ -v "SCENARIO_MAP[$SCENARIO]" ]; then
|
||||||
|
SCENARIO="${SCENARIO_MAP[$SCENARIO]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 验证 ──────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo -e "${CYAN} Siemens RAGAS — 评估运行${NC}"
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 检查虚拟环境
|
||||||
|
if [ ! -f ".venv/bin/python" ]; then
|
||||||
|
err "未找到 .venv,请先执行部署:bash deploy.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHON=".venv/bin/python"
|
||||||
|
|
||||||
|
# Build 模式校验
|
||||||
|
if [ "$BUILD_MODE" = true ]; then
|
||||||
|
if [ ! -f "$BUILD_CONFIG" ]; then
|
||||||
|
err "题库生成配置文件不存在:$BUILD_CONFIG"
|
||||||
|
echo ""
|
||||||
|
echo "可用配置:"
|
||||||
|
find scenarios/ -name "*.yaml" 2>/dev/null | head -20 | sed 's/^/ /'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ok "模式 : 题库生成 (dataset build)"
|
||||||
|
ok "配置文件 : $BUILD_CONFIG"
|
||||||
|
else
|
||||||
|
# 场景文件校验
|
||||||
|
if [ ! -f "$SCENARIO" ]; then
|
||||||
|
err "场景文件不存在:$SCENARIO"
|
||||||
|
echo ""
|
||||||
|
echo "用法示例:"
|
||||||
|
echo " bash run_eval.sh # online 评估"
|
||||||
|
echo " bash run_eval.sh offline # offline 冒烟"
|
||||||
|
echo " bash run_eval.sh scenarios/xxx.yaml # 自定义场景"
|
||||||
|
echo " bash run_eval.sh build [config.yaml] # 题库生成"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ok "场景文件 : $SCENARIO"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 日志级别校验
|
||||||
|
LOG_LEVEL_UPPER="${LOG_LEVEL^^}"
|
||||||
|
case "$LOG_LEVEL_UPPER" in
|
||||||
|
DEBUG|INFO|WARNING|ERROR) ;;
|
||||||
|
*)
|
||||||
|
warn "未知日志级别 '$LOG_LEVEL',使用默认值 INFO"
|
||||||
|
LOG_LEVEL_UPPER="INFO"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
ok "日志级别 : $LOG_LEVEL_UPPER"
|
||||||
|
|
||||||
|
# 创建日志目录
|
||||||
|
mkdir -p logs
|
||||||
|
TIMESTAMP=$(date +%Y-%m-%d_%H%M%S)
|
||||||
|
LOG_FILE="logs/eval_${TIMESTAMP}.log"
|
||||||
|
ok "日志文件 : $LOG_FILE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo -e "${CYAN} 开始运行,按 Ctrl+C 中止${NC}"
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ── 运行 ──────────────────────────────────────────────────────────
|
||||||
|
export PYTHONIOENCODING="utf-8"
|
||||||
|
export PYTHONPATH="."
|
||||||
|
|
||||||
|
if [ "$BUILD_MODE" = true ]; then
|
||||||
|
"$PYTHON" main.py \
|
||||||
|
--dataset-build-config "$BUILD_CONFIG"
|
||||||
|
else
|
||||||
|
"$PYTHON" main.py \
|
||||||
|
--scenario "$SCENARIO" \
|
||||||
|
--log-file "$LOG_FILE" \
|
||||||
|
--log-level "$LOG_LEVEL_UPPER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXIT_CODE=$?
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
if [ $EXIT_CODE -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}============================================================${NC}"
|
||||||
|
echo -e "${GREEN} 运行完成!${NC}"
|
||||||
|
if [ "$BUILD_MODE" = false ]; then
|
||||||
|
echo -e "${GREEN} 日志已保存到:$LOG_FILE${NC}"
|
||||||
|
fi
|
||||||
|
echo -e "${CYAN} 在 Web 控制台查看报告:bash start.sh${NC}"
|
||||||
|
echo -e "${GREEN}============================================================${NC}"
|
||||||
|
else
|
||||||
|
err "运行失败(exit code=$EXIT_CODE)"
|
||||||
|
if [ "$BUILD_MODE" = false ]; then
|
||||||
|
err "查看日志:cat $LOG_FILE"
|
||||||
|
fi
|
||||||
|
exit $EXIT_CODE
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
94
start.sh
Normal file
94
start.sh
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# start.sh — 启动 Siemens RAGAS Web 服务(后台运行)
|
||||||
|
# 前提:已执行过 deploy.sh(.venv 和依赖均已就绪)
|
||||||
|
# 用法:bash start.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# ── 颜色输出 ──────────────────────────────────────────────────────
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
else
|
||||||
|
GREEN=''; YELLOW=''; RED=''; CYAN=''; NC=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo -e "${CYAN} Siemens RAGAS Console — 启动服务${NC}"
|
||||||
|
echo -e "${CYAN}============================================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 检查虚拟环境
|
||||||
|
if [ ! -f ".venv/bin/python" ]; then
|
||||||
|
err "未找到 .venv,请先执行部署:bash deploy.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHON=".venv/bin/python"
|
||||||
|
|
||||||
|
# 检查 .env
|
||||||
|
if [ ! -f ".env" ]; then
|
||||||
|
warn ".env 不存在,请先复制并编辑配置:"
|
||||||
|
warn " cp .env.example .env && nano .env"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "your-api-key" .env 2>/dev/null; then
|
||||||
|
warn ".env 中仍包含默认占位符,部分功能(评估执行)将不可用"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查是否已有运行中的进程
|
||||||
|
if [ -f ".server.pid" ]; then
|
||||||
|
EXISTING_PID=$(cat .server.pid)
|
||||||
|
if kill -0 "$EXISTING_PID" 2>/dev/null; then
|
||||||
|
warn "服务已在运行 (PID=$EXISTING_PID),无需重复启动"
|
||||||
|
warn "如需重启请先执行:bash stop.sh"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
# PID 文件残留,清理
|
||||||
|
rm -f .server.pid
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建必要目录
|
||||||
|
mkdir -p logs
|
||||||
|
|
||||||
|
# 端口检测
|
||||||
|
PORT=8800
|
||||||
|
if ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||||
|
warn "端口 $PORT 已被占用,尝试 8801..."
|
||||||
|
PORT=8801
|
||||||
|
if ss -tlnp 2>/dev/null | grep -q ":$PORT " || netstat -tlnp 2>/dev/null | grep -q ":$PORT "; then
|
||||||
|
err "端口 8800 和 8801 均被占用,请手动指定端口:"
|
||||||
|
err " .venv/bin/python webmain.py --host 0.0.0.0 --port <PORT>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 后台启动
|
||||||
|
nohup "$PYTHON" webmain.py --host 0.0.0.0 --port "$PORT" >> logs/server.log 2>&1 &
|
||||||
|
SERVER_PID=$!
|
||||||
|
echo "$SERVER_PID" > .server.pid
|
||||||
|
|
||||||
|
# 等待 3 秒验证进程存活
|
||||||
|
sleep 3
|
||||||
|
if kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||||
|
ok "服务已启动 (PID=$SERVER_PID)"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN} 访问地址: http://$(hostname -I | awk '{print $1}'):${PORT}${NC}"
|
||||||
|
echo -e "${CYAN} 本机访问: http://127.0.0.1:${PORT}${NC}"
|
||||||
|
echo -e "${CYAN} 查看日志: tail -f logs/server.log${NC}"
|
||||||
|
echo -e "${CYAN} 停止服务: bash stop.sh${NC}"
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
err "服务启动失败,请查看日志:"
|
||||||
|
err " tail -20 logs/server.log"
|
||||||
|
rm -f .server.pid
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
68
stop.sh
Normal file
68
stop.sh
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# stop.sh — 停止 Siemens RAGAS 后台 Web 服务
|
||||||
|
# 用法:bash stop.sh
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# ── 颜色输出 ──────────────────────────────────────────────────────
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
else
|
||||||
|
GREEN=''; YELLOW=''; RED=''; CYAN=''; NC=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN} Siemens RAGAS Console — 停止服务${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
PID_FILE="$SCRIPT_DIR/.server.pid"
|
||||||
|
|
||||||
|
if [ ! -f "$PID_FILE" ]; then
|
||||||
|
warn "未找到 .server.pid,服务可能未启动或已停止"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
PID=$(cat "$PID_FILE")
|
||||||
|
|
||||||
|
if ! kill -0 "$PID" 2>/dev/null; then
|
||||||
|
warn "进程 $PID 已不存在,清理 PID 文件"
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 优雅停止(SIGTERM)
|
||||||
|
echo -e " 正在停止进程 (PID=$PID)..."
|
||||||
|
kill "$PID" 2>/dev/null || true
|
||||||
|
|
||||||
|
# 等待最多 5 秒
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
sleep 1
|
||||||
|
if ! kill -0 "$PID" 2>/dev/null; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo -e " 等待进程退出... ($i/5)"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 若进程仍存在,强制终止
|
||||||
|
if kill -0 "$PID" 2>/dev/null; then
|
||||||
|
warn "进程未响应,强制终止 (SIGKILL)..."
|
||||||
|
kill -9 "$PID" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
|
||||||
|
if kill -0 "$PID" 2>/dev/null; then
|
||||||
|
err "无法停止进程 $PID,请手动执行:kill -9 $PID"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
ok "服务已停止"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user