- Extract backend_accounting from llmage cleanupctx to independent process - Add bin/backend_accounting.py for standalone LLM billing loop - Rewrite start.sh with two-phase startup: 1. Independent backend programs (run once) 2. Sage Web workers (SO_REUSEPORT on same port) - Rewrite stop.sh to handle both workers and backend processes - Add .gitignore for build artifacts and runtime files Architecture: - CPU core detection for worker count - All workers share port 9180 via SO_REUSEPORT - Backend processes tracked in sage_backend.pid - Workers tracked in sage.pid
116 lines
3.1 KiB
Bash
Executable File
116 lines
3.1 KiB
Bash
Executable File
#!/bin/bash
|
|
# Sage Web Application Stop Script
|
|
# 停止所有 Web Workers 和独立后台程序
|
|
|
|
set -e
|
|
|
|
# 切换到脚本所在目录
|
|
cd "$(dirname "$0")"
|
|
|
|
WORKDIR="$(pwd)"
|
|
PIDFILE="$WORKDIR/sage.pid"
|
|
BINPIDFILE="$WORKDIR/sage_backend.pid"
|
|
|
|
echo "========================================="
|
|
echo "停止 Sage Web Application"
|
|
echo "========================================="
|
|
|
|
# =========================================
|
|
# 步骤 1: 停止 Web Workers
|
|
# =========================================
|
|
echo ""
|
|
echo "--- 停止 Web Workers ---"
|
|
|
|
if [ -f "$PIDFILE" ]; then
|
|
echo "读取 Worker PID 文件..."
|
|
|
|
while IFS= read -r pid || [ -n "$pid" ]; do
|
|
pid=$(echo "$pid" | tr -d '[:space:]')
|
|
[ -z "$pid" ] && continue
|
|
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "正在停止 Worker (PID: $pid) ..."
|
|
kill "$pid" 2>/dev/null || true
|
|
else
|
|
echo "Worker (PID: $pid) 已不在运行"
|
|
fi
|
|
done < "$PIDFILE"
|
|
|
|
# 等待进程退出
|
|
echo "等待服务关闭..."
|
|
for i in $(seq 1 10); do
|
|
all_stopped=true
|
|
while IFS= read -r pid || [ -n "$pid" ]; do
|
|
pid=$(echo "$pid" | tr -d '[:space:]')
|
|
[ -z "$pid" ] && continue
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
all_stopped=false
|
|
break
|
|
fi
|
|
done < "$PIDFILE"
|
|
|
|
if $all_stopped; then
|
|
echo "所有 Worker 已停止 (用时 ${i}s)"
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# 强制杀死仍在运行的进程
|
|
while IFS= read -r pid || [ -n "$pid" ]; do
|
|
pid=$(echo "$pid" | tr -d '[:space:]')
|
|
[ -z "$pid" ] && continue
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "强制停止 Worker (PID: $pid)"
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
fi
|
|
done < "$PIDFILE"
|
|
|
|
# 清理 PID 文件
|
|
rm -f "$PIDFILE"
|
|
else
|
|
echo "未找到 Worker PID 文件 ($PIDFILE)"
|
|
fi
|
|
|
|
# =========================================
|
|
# 步骤 2: 停止独立后台程序
|
|
# =========================================
|
|
echo ""
|
|
echo "--- 停止独立后台程序 ---"
|
|
|
|
if [ -f "$BINPIDFILE" ]; then
|
|
echo "读取后台程序 PID 文件..."
|
|
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
line=$(echo "$line" | tr -d '[:space:]')
|
|
[ -z "$line" ] && continue
|
|
|
|
# 格式: name:pid
|
|
name="${line%%:*}"
|
|
pid="${line##*:}"
|
|
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "正在停止 $name (PID: $pid) ..."
|
|
kill "$pid" 2>/dev/null || true
|
|
sleep 1
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "强制停止 $name (PID: $pid)"
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
fi
|
|
echo " -> $name 已停止"
|
|
else
|
|
echo "$name (PID: $pid) 已不在运行"
|
|
fi
|
|
done < "$BINPIDFILE"
|
|
|
|
# 清理 PID 文件
|
|
rm -f "$BINPIDFILE"
|
|
else
|
|
echo "未找到后台程序 PID 文件 ($BINPIDFILE)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo "所有服务已停止"
|
|
echo "========================================="
|