Files
zkxw/backend/start-test.sh
T
zlwuandCursor db31990ebe feat: 细胞存储缴费催缴、统一样本信息与协议支付能力增强
汇总近期业务改动:催缴菜单与后端、样本信息快捷登记与进度、运费关联、客户档案扩展、协议优惠/期次与押金划转,并同步 SQL 迁移与管理端页面收敛。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 21:20:37 +08:00

358 lines
8.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================
# 陇耘鲜达 Backend 测试环境启动脚本
# 适配: python3.9+(推荐 venv;显式不使用 python2)
#
# 测试服务器目录示例: /root/zkxw/backend
# 默认监听: 127.0.0.1:10002(裸机 Nginx 反代;勿与生产 8111 冲突)
# 旧双机拓扑 0.0.0.0:8112 已废弃;手动 start/restart 时也走本默认,避免 Nginx 502。
#
# 首次部署:
# cd /root/zkxw/backend
# cp .env.test.example .env.test # 或从 .env.example 复制后按测试库填写
# python3.9 -m venv .venv && ./.venv/bin/pip install -r requirements.txt
# ./start-test.sh activate # source .venv/bin/activate
# ./start-test.sh start
# ============================================
set -euo pipefail
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$BASE_DIR"
APP_MODULE="${APP_MODULE:-app.main:app}"
HOST="${HOST:-127.0.0.1}"
PORT="${PORT:-10002}"
WORKERS="${WORKERS:-1}"
LOG_LEVEL="${LOG_LEVEL:-debug}"
ENV_FILE="${ENV_FILE:-$BASE_DIR/.env.test}"
VENV_DIR="${VENV_DIR:-$BASE_DIR/.venv}"
ACTIVATE_SCRIPT="$VENV_DIR/bin/activate"
PYTHON_BIN="${PYTHON_BIN:-$VENV_DIR/bin/python}"
MIN_PYTHON_MAJOR=3
MIN_PYTHON_MINOR=9
SYSTEM_PYTHON=""
LOG_DIR="$BASE_DIR/logs"
LOG_FILE="$LOG_DIR/backend-test.log"
PID_FILE="$BASE_DIR/backend-test.pid"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
show_help() {
cat << 'EOF'
用法:
./start-test.sh [start|stop|restart|status|logs|activate]
命令:
start 启动服务(默认)
stop 停止服务
restart 重启服务
status 查看状态
logs 查看日志(最近100行)
activate 激活 .venv 并进入交互 shell(等价 source .venv/bin/activate)
可选环境变量:
HOST=127.0.0.1
PORT=10002
WORKERS=1
LOG_LEVEL=debug
APP_MODULE=app.main:app
VENV_DIR=./.venv
PYTHON_FOR_VENV=python3.9
ENV_FILE=./.env.test
测试部署目录(示例):
/root/zkxw/backend
cd /root/zkxw/backend && ./start-test.sh start
说明:
- 读取 .env.test(非 .env.production)
- 默认 127.0.0.1:10002(Nginx 反代);生产 start-prod.sh 使用 8111
- 可与生产共用 venv,但 PID/日志文件独立,勿混用 start/stop 命令
EOF
}
ensure_dirs() {
mkdir -p "$LOG_DIR"
}
python_version_ge() {
local ver="$1"
local major="${ver%%.*}"
local minor="${ver#*.}"
if [ "$major" -gt "$MIN_PYTHON_MAJOR" ]; then
return 0
fi
if [ "$major" -eq "$MIN_PYTHON_MAJOR" ] && [ "$minor" -ge "$MIN_PYTHON_MINOR" ]; then
return 0
fi
return 1
}
resolve_system_python() {
local candidate ver
if [ -n "${PYTHON_FOR_VENV:-}" ] && command -v "$PYTHON_FOR_VENV" >/dev/null 2>&1; then
ver="$("$PYTHON_FOR_VENV" -c 'import sys; print("{}.{}".format(sys.version_info[0], sys.version_info[1]))')"
if python_version_ge "$ver"; then
echo "$PYTHON_FOR_VENV"
return 0
fi
log_error "PYTHON_FOR_VENV=$PYTHON_FOR_VENV 版本为 $ver,需要 >= ${MIN_PYTHON_MAJOR}.${MIN_PYTHON_MINOR}"
exit 1
fi
for candidate in python3.11 python3.10 python3.9 python3; do
if command -v "$candidate" >/dev/null 2>&1; then
ver="$("$candidate" -c 'import sys; print("{}.{}".format(sys.version_info[0], sys.version_info[1]))')"
if python_version_ge "$ver"; then
echo "$candidate"
return 0
fi
fi
done
return 1
}
check_python() {
if ! SYSTEM_PYTHON="$(resolve_system_python)"; then
log_error "未找到 python${MIN_PYTHON_MAJOR}.${MIN_PYTHON_MINOR}+,请安装 python39 或设置 PYTHON_FOR_VENV=python3.9"
exit 1
fi
log_info "系统 Python: $SYSTEM_PYTHON ($("$SYSTEM_PYTHON" --version 2>&1))"
}
ensure_venv_python_version() {
local ver
ver="$("$PYTHON_BIN" -c 'import sys; print("{}.{}".format(sys.version_info[0], sys.version_info[1]))')"
if python_version_ge "$ver"; then
log_info "虚拟环境 Python: $ver ($VENV_DIR)"
return 0
fi
log_error "虚拟环境 Python 版本过低: $ver(需要 >= ${MIN_PYTHON_MAJOR}.${MIN_PYTHON_MINOR})"
log_error "当前虚拟环境目录: $VENV_DIR"
log_warn "请执行: rm -rf \"$VENV_DIR\" && $SYSTEM_PYTHON -m venv \"$VENV_DIR\" && \"$VENV_DIR/bin/pip\" install -r requirements.txt"
exit 1
}
has_uvicorn() {
"$PYTHON_BIN" -c "import uvicorn" >/dev/null 2>&1
}
ensure_venv_and_runtime() {
log_info "虚拟环境目录: $VENV_DIR"
if [ ! -d "$VENV_DIR" ]; then
log_warn "未找到虚拟环境,开始自动创建: $VENV_DIR"
if ! "$SYSTEM_PYTHON" -m venv "$VENV_DIR" >/dev/null 2>&1; then
log_error "自动创建 venv 失败,请先安装 python3-venv 或手动创建虚拟环境"
log_warn "可尝试: $SYSTEM_PYTHON -m venv \"$VENV_DIR\""
exit 1
fi
fi
if [ ! -x "$PYTHON_BIN" ]; then
log_error "虚拟环境 python 不存在: $PYTHON_BIN"
exit 1
fi
ensure_venv_python_version
if [ ! -x "$VENV_DIR/bin/pip" ]; then
log_warn "虚拟环境 pip 不存在,尝试引导安装"
"$PYTHON_BIN" -m ensurepip --upgrade >/dev/null 2>&1 || true
fi
if ! has_uvicorn; then
log_warn "未检测到 uvicorn,开始安装依赖 requirements.txt"
if [ ! -x "$VENV_DIR/bin/pip" ]; then
log_error "pip 仍不可用,请手动执行依赖初始化"
exit 1
fi
"$VENV_DIR/bin/pip" install --upgrade pip
"$VENV_DIR/bin/pip" install -r "$BASE_DIR/requirements.txt"
if ! has_uvicorn; then
log_error "依赖安装后仍无法 import uvicorn,请检查: $PYTHON_BIN -m pip install -r requirements.txt"
exit 1
fi
fi
}
is_running() {
if [ ! -f "$PID_FILE" ]; then
return 1
fi
local pid
pid="$(cat "$PID_FILE")"
if [ -z "$pid" ]; then
return 1
fi
if ps -p "$pid" >/dev/null 2>&1; then
return 0
fi
return 1
}
start_server() {
check_python
ensure_venv_and_runtime
ensure_dirs
if is_running; then
local running_pid
running_pid="$(cat "$PID_FILE")"
log_warn "测试服务已在运行 (PID: $running_pid)"
exit 0
fi
if [ -f "$PID_FILE" ]; then
rm -f "$PID_FILE"
fi
log_info "启动测试环境服务..."
log_info "监听地址: $HOST:$PORT"
log_info "工作进程: $WORKERS"
log_info "日志文件: $LOG_FILE"
log_info "环境文件: $ENV_FILE"
if [ ! -f "$ENV_FILE" ]; then
log_error "环境文件不存在: $ENV_FILE"
log_warn "可先执行: cp .env.test.example .env.test 并按测试库修改"
exit 1
fi
export ENV_FILE
nohup "$PYTHON_BIN" -m uvicorn "$APP_MODULE" \
--host "$HOST" \
--port "$PORT" \
--workers "$WORKERS" \
--log-level "$LOG_LEVEL" \
>> "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
sleep 2
if is_running; then
log_info "测试服务启动成功 (PID: $(cat "$PID_FILE"))"
log_info "健康检查: http://127.0.0.1:$PORT/health"
log_info "API 文档: http://127.0.0.1:$PORT/docs"
else
log_error "测试服务启动失败,请检查日志: $LOG_FILE"
rm -f "$PID_FILE"
exit 1
fi
}
stop_server() {
if ! is_running; then
log_warn "测试服务未运行"
[ -f "$PID_FILE" ] && rm -f "$PID_FILE"
# 用 return 而非 exit,避免 restart 在「已停止」时整脚本退出、无法再 start
return 0
fi
local pid
pid="$(cat "$PID_FILE")"
log_info "正在停止测试服务 (PID: $pid)"
kill -TERM "$pid" >/dev/null 2>&1 || true
for _ in 1 2 3 4 5 6 7 8 9 10; do
if ! ps -p "$pid" >/dev/null 2>&1; then
break
fi
sleep 1
done
if ps -p "$pid" >/dev/null 2>&1; then
log_warn "优雅停止超时,执行强制停止"
kill -9 "$pid" >/dev/null 2>&1 || true
fi
rm -f "$PID_FILE"
log_info "测试服务已停止"
}
status_server() {
if is_running; then
echo -e "${GREEN}RUNNING (test)${NC} PID=$(cat "$PID_FILE") HOST=$HOST PORT=$PORT"
else
echo -e "${RED}STOPPED (test)${NC}"
fi
}
show_logs() {
ensure_dirs
if [ ! -f "$LOG_FILE" ]; then
log_warn "暂无日志文件: $LOG_FILE"
exit 0
fi
tail -n 100 "$LOG_FILE"
}
activate_venv() {
if [ ! -f "$ACTIVATE_SCRIPT" ]; then
log_error "虚拟环境激活脚本不存在: $ACTIVATE_SCRIPT"
log_warn "可先执行: python3.9 -m venv .venv && ./.venv/bin/pip install -r requirements.txt"
exit 1
fi
log_info "激活虚拟环境: source $ACTIVATE_SCRIPT"
exec "$SHELL" -i -c "cd '$BASE_DIR' && source '$ACTIVATE_SCRIPT' && exec -i '$SHELL'"
}
ACTION="${1:-start}"
case "$ACTION" in
start)
start_server
;;
stop)
stop_server
;;
restart)
stop_server || true
start_server
;;
status)
status_server
;;
logs)
show_logs
;;
activate)
activate_venv
;;
-h|--help|help)
show_help
;;
*)
log_error "未知命令: $ACTION"
show_help
exit 1
;;
esac