Files
evotraders/start.sh
cillin ecc7623093 refactor(openclaw): remove REST facade (port 8004), unify on WebSocket
Remove the redundant OpenClaw REST service (port 8004) since frontend
already uses WebSocket via Gateway (port 8765) → OpenClaw (port 18789).

Deleted:
- backend/apps/openclaw_service.py
- backend/api/openclaw.py
- backend/tests/test_openclaw_service_app.py
- backend/tests/test_service_clients.py
- shared/client/openclaw_client.py

Updated:
- backend/apps/__init__.py — remove openclaw_app exports
- backend/api/__init__.py — remove openclaw_router
- shared/client/__init__.py — remove OpenClawServiceClient
- backend/services/gateway_openclaw_handlers.py — update docstring
- start.sh — remove port 8004 service startup

Architecture:
- Before: Frontend → HTTP :8004 → subprocess openclaw CLI
- After: Frontend → WS :8765 → Gateway → WS :18789 → OpenClaw

Constraint: Frontend already uses WebSocket exclusively
Confidence: high
Scope-risk: low (frontend unchanged)
2026-04-02 11:04:06 +08:00

330 lines
9.4 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.
#!/usr/bin/env bash
# ============================================================
# 大时代 生产环境启动脚本
#
# 用法:
# ./start.sh # 构建前端 + 后台启动全部服务 (默认)
# ./start.sh --no-build # 跳过前端构建
# ./start.sh --no-daemon # 前台运行 (不使用 nohup)
# ./start.sh --gateway-only # 仅启动 Gateway (配合 nginx)
# ./start.sh stop # 停止所有后台服务
# ./start.sh status # 查看服务状态
#
# 环境变量:
# WORKERS=2 # uvicorn worker 数 (默认: 2)
# GATEWAY_HOST=0.0.0.0 # Gateway 绑定地址
# GATEWAY_PORT=8765 # Gateway 端口
# FRONTEND_PORT=80 # 前端服务端口 (默认: 80)
# ============================================================
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${SCRIPT_DIR}"
WORKERS="${WORKERS:-2}"
GATEWAY_HOST="${GATEWAY_HOST:-0.0.0.0}"
GATEWAY_PORT="${GATEWAY_PORT:-8765}"
FRONTEND_PORT="${FRONTEND_PORT:-80}"
PID_DIR="${SCRIPT_DIR}/.pids"
LOG_DIR="${SCRIPT_DIR}/logs"
FRONTEND_DIST="${SCRIPT_DIR}/frontend/dist"
DAEMON=true
BUILD_FRONTEND=true
GATEWAY_ONLY=false
ACTION="start"
for arg in "$@"; do
case "$arg" in
--no-daemon) DAEMON=false ;;
--no-build) BUILD_FRONTEND=false ;;
--gateway-only) GATEWAY_ONLY=true ;;
stop) ACTION="stop" ;;
status) ACTION="status" ;;
*) echo -e "${YELLOW}忽略未知参数: ${arg}${NC}" ;;
esac
done
ensure_dirs() {
mkdir -p "${PID_DIR}" "${LOG_DIR}"
}
save_pid() {
local name="$1" pid="$2"
echo "${pid}" > "${PID_DIR}/${name}.pid"
}
read_pid() {
local name="$1"
local pidfile="${PID_DIR}/${name}.pid"
if [ -f "${pidfile}" ]; then
cat "${pidfile}"
fi
}
is_running() {
local pid="$1"
[ -n "${pid}" ] && kill -0 "${pid}" 2>/dev/null
}
stop_service() {
local name="$1"
local pid
pid="$(read_pid "${name}")"
if is_running "${pid}"; then
echo -e " ${YELLOW}停止${NC} ${name} (PID: ${pid})"
kill "${pid}" 2>/dev/null || true
local count=0
while is_running "${pid}" && [ "${count}" -lt 20 ]; do
sleep 0.5
count=$((count + 1))
done
if is_running "${pid}"; then
echo -e " ${RED}强制终止${NC} ${name}"
kill -9 "${pid}" 2>/dev/null || true
fi
fi
rm -f "${PID_DIR}/${name}.pid"
}
print_status() {
local name="$1" port="$2"
local pid
pid="$(read_pid "${name}")"
if is_running "${pid}"; then
echo -e " ${GREEN}${NC} ${name} (PID: ${pid}, 端口: ${port})"
else
echo -e " ${RED}${NC} ${name} (未运行)"
fi
}
load_env() {
if [ -f .env ]; then
set -a
# shellcheck disable=SC1091
source .env
set +a
else
echo -e "${YELLOW}警告: 未检测到 .env将使用环境变量或默认值${NC}"
fi
}
check_prereqs() {
# Resolve the Python interpreter to use. Prefer the project venv.
if [ -x "${SCRIPT_DIR}/.venv/bin/python" ]; then
PYTHON="${SCRIPT_DIR}/.venv/bin/python"
else
PYTHON="$(command -v python3 2>/dev/null || command -v python 2>/dev/null || true)"
fi
if [ -z "${PYTHON}" ]; then
echo -e "${RED}未找到 python${NC}"
exit 1
fi
echo -e "${GREEN}使用 Python: ${PYTHON}${NC}"
command -v lsof >/dev/null 2>&1 || {
echo -e "${RED}未找到 lsof${NC}"
exit 1
}
}
kill_port() {
local port="$1"
local pids
pids="$(lsof -ti :"${port}" 2>/dev/null || true)"
if [ -n "${pids}" ]; then
echo -e "${YELLOW}端口 ${port} 已被占用,清理 PID:${NC} ${pids}"
echo "${pids}" | xargs kill -9 2>/dev/null || true
sleep 0.5
fi
}
do_stop() {
echo -e "${CYAN}停止所有服务...${NC}"
for svc in frontend agent_service trading_service news_service runtime_service; do
stop_service "${svc}"
done
echo -e "${GREEN}已停止${NC}"
}
do_status() {
echo ""
echo -e "${CYAN}服务状态${NC}"
print_status "agent_service" 8000
print_status "trading_service" 8001
print_status "news_service" 8002
print_status "runtime_service" 8003
print_status "frontend" "${FRONTEND_PORT}"
echo ""
echo -e " ${CYAN}${NC} Gateway 由 runtime_service 管理,通过前端启动任务触发"
echo ""
if [ -d "${FRONTEND_DIST}" ]; then
echo -e " ${GREEN}${NC} 前端已构建: ${FRONTEND_DIST}"
else
echo -e " ${YELLOW}${NC} 前端未构建,运行: cd frontend && npm run build"
fi
echo ""
}
build_frontend() {
if ! ${BUILD_FRONTEND}; then
return
fi
echo ""
echo -e "${CYAN}构建前端...${NC}"
if [ -d "frontend" ] && command -v npm >/dev/null 2>&1; then
if [ -f "frontend/package-lock.json" ]; then
(cd frontend && npm ci && npm run build)
else
(cd frontend && npm install && npm run build)
fi
echo -e "${GREEN}前端构建完成: ${FRONTEND_DIST}${NC}"
else
echo -e "${RED}前端构建失败: 需要 npm 和 frontend 目录${NC}"
exit 1
fi
}
start_single_daemon() {
local name="$1" app_path="$2" port="$3"
echo -e " ${GREEN}${NC} ${name} → :${port} (${WORKERS} workers)"
nohup env SERVICE_NAME="${name}" "${PYTHON}" -m uvicorn "${app_path}" \
--host 0.0.0.0 \
--port "${port}" \
--workers "${WORKERS}" \
--log-level warning \
--no-access-log \
>> "${LOG_DIR}/${name}.log" 2>&1 &
save_pid "${name}" $!
}
start_daemon() {
if ! ${GATEWAY_ONLY}; then
start_single_daemon "agent_service" "backend.apps.agent_service:app" 8000
start_single_daemon "trading_service" "backend.apps.trading_service:app" 8001
start_single_daemon "news_service" "backend.apps.news_service:app" 8002
start_single_daemon "runtime_service" "backend.apps.runtime_service:app" 8003
fi
echo -e " ${GREEN}${NC} frontend → http://0.0.0.0:${FRONTEND_PORT}"
nohup env SERVICE_NAME="frontend" "${PYTHON}" -m uvicorn "backend.apps.frontend_service:app" \
--host 0.0.0.0 \
--port "${FRONTEND_PORT}" \
--workers "${WORKERS}" \
--log-level warning \
--no-access-log \
>> "${LOG_DIR}/frontend.log" 2>&1 &
save_pid "frontend" $!
echo ""
echo -e "${GREEN}所有服务已在后台启动${NC}"
echo " 日志目录: ${LOG_DIR}/"
echo " PID 目录: ${PID_DIR}/"
echo ""
echo " 查看状态: ./start.sh status"
echo " 查看日志: tail -f ${LOG_DIR}/gateway.log"
echo " 停止服务: ./start.sh stop"
echo ""
}
PIDS=()
cleanup_foreground() {
echo ""
echo -e "${YELLOW}正在停止所有服务...${NC}"
if [ "${#PIDS[@]}" -gt 0 ]; then
kill "${PIDS[@]}" 2>/dev/null || true
wait "${PIDS[@]}" 2>/dev/null || true
fi
}
start_single_foreground() {
local name="$1" app_path="$2" port="$3"
echo -e " ${GREEN}${NC} ${name} → :${port}"
env SERVICE_NAME="${name}" "${PYTHON}" -m uvicorn "${app_path}" \
--host 0.0.0.0 \
--port "${port}" \
--log-level warning \
--no-access-log &
PIDS+=($!)
}
start_foreground() {
trap cleanup_foreground EXIT INT TERM
if ! ${GATEWAY_ONLY}; then
start_single_foreground "agent_service" "backend.apps.agent_service:app" 8000
start_single_foreground "trading_service" "backend.apps.trading_service:app" 8001
start_single_foreground "news_service" "backend.apps.news_service:app" 8002
start_single_foreground "runtime_service" "backend.apps.runtime_service:app" 8003
fi
echo -e " ${GREEN}${NC} frontend → http://0.0.0.0:${FRONTEND_PORT}"
env SERVICE_NAME="frontend" "${PYTHON}" -m uvicorn "backend.apps.frontend_service:app" \
--host 0.0.0.0 \
--port "${FRONTEND_PORT}" \
--log-level warning \
--no-access-log &
PIDS+=($!)
echo ""
echo -e "${GREEN}服务以前台模式运行。按 Ctrl+C 停止。${NC}"
wait
}
do_start() {
ensure_dirs
check_prereqs
load_env
export TRADING_SERVICE_URL="${TRADING_SERVICE_URL:-http://localhost:8001}"
export NEWS_SERVICE_URL="${NEWS_SERVICE_URL:-http://localhost:8002}"
export RUNTIME_SERVICE_URL="${RUNTIME_SERVICE_URL:-http://localhost:8003}"
build_frontend
echo ""
echo -e "${CYAN}停止已有服务...${NC}"
for svc in frontend agent_service trading_service news_service runtime_service; do
stop_service "${svc}"
done
echo ""
echo -e "${CYAN}══════════════════════════════════════════${NC}"
echo -e "${CYAN} 大时代 · 生产环境启动${NC}"
echo -e "${CYAN}══════════════════════════════════════════${NC}"
echo ""
if ${DAEMON}; then
start_daemon
else
start_foreground
fi
}
case "${ACTION}" in
start)
do_start
;;
stop)
do_stop
;;
status)
do_status
;;
*)
echo -e "${RED}未知动作: ${ACTION}${NC}"
exit 1
;;
esac