Files
Agent-System/scripts/launch-single.sh
T
weichen d91dafc1c4 feat(scripts): test env single-binary entrypoints (migrate-test-db, launch-single)
- migrate-test-db.sh: reuse parameterized migrate-dev-db.sh with test defaults
  (container shuimu-system-pg-test -> localpg :5434, PGDATA=data/test/pg)
- launch-single.sh: non-dev single-binary launcher (SYSTEM_DB_*->CONTEXT_DB_*
  mapping, env-scoped PI sidecar, no Vite); task record for dev->test rc
  promotion + test conversion (rc-v1.1.0-beta.4)
2026-09-27 16:21:09 +00:00

164 lines
5.9 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
# launch-single.sh — 非容器单二进制启动入口(非 dev 环境;当前用于 test)
#
# 与 launch.sh --no-docker(dev 专用:含 Vite/热更)相对,本脚本服务长期部署形态:
# - PI sidecar(环境专属端口/工作区)+ agent-server 单二进制(embed 静态,无 Vite)
# - LOCALPG_MODE 默认 managed(PGDATA=$DATA_DIR/pg,端口沿用环境约定)
# - 从 configs/.env.<env> + 根 .env 分层加载配置;SYSTEM_DB_*(compose 约定)
# 在此映射为宿主运行所需 CONTEXT_DB_*
#
# 用法:
# ./scripts/launch-single.sh test [--bin /path/to/agent-server] [--build]
# --bin 指定二进制路径(默认 bin/agent-server-<env>)
# --build 从当前工作树构建。test 部署应使用 rc tag 构建的制品,勿默认依赖 --build
#
# 日志:.tmp/launch/{server,pi-sidecar}-<env>.log
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_NAME=""
if [[ $# -gt 0 && "${1:0:1}" != "-" ]]; then
ENV_NAME="$1"
shift
fi
BIN_OVERRIDE=""
DO_BUILD=0
while [[ $# -gt 0 ]]; do
case "$1" in
--bin) BIN_OVERRIDE="${2:-}"; shift 2 ;;
--build) DO_BUILD=1; shift ;;
-h|--help)
sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*) echo "unknown arg: $1" >&2; exit 1 ;;
esac
done
if [[ -z "$ENV_NAME" || "$ENV_NAME" == "dev" ]]; then
echo "error: dev 请使用 ./scripts/launch.sh --no-docker;本脚本用于非 dev 环境(如 test)" >&2
exit 1
fi
LOG_DIR="$ROOT/.tmp/launch"
mkdir -p "$LOG_DIR"
info() { printf '\033[1;34m[launch-single]\033[0m %s\n' "$*"; }
ok() { printf '\033[1;32m ✅ %s\033[0m\n' "$*"; }
skip() { printf '\033[1;32m ⏭️ %s\033[0m\n' "$*"; }
act() { printf '\033[1;33m 🔄 %s\033[0m\n' "$*"; }
fail() { printf '\033[1;31m ❌ %s\033[0m\n' "$*"; }
# ---------- 分层加载配置:根 .env(公共密钥)→ configs/.env.<env>(环境差异) ----------
# shellcheck disable=SC1091
set -a
[[ -f "$ROOT/.env" ]] && . "$ROOT/.env"
if [[ -f "$ROOT/configs/.env.$ENV_NAME" ]]; then
. "$ROOT/configs/.env.$ENV_NAME"
else
fail "缺少 configs/.env.$ENV_NAME(参考 configs/.env.$ENV_NAME.example)"
exit 1
fi
set +a
# ---------- 宿主运行派生(进程环境变量优先于 .env 文件) ----------
export ENV="$ENV_NAME"
DATA_DIR="${DATA_DIR:-$ROOT/data/$ENV_NAME}"
case "$DATA_DIR" in /*) ;; *) DATA_DIR="$ROOT/$DATA_DIR" ;; esac
export DATA_DIR
HTTP_PORT="${HTTP_PORT:-8081}"
export HTTP_HOST="${HTTP_HOST:-${APP_PUBLISH_HOST:-0.0.0.0}}"
export HTTP_PORT
export SEED_DEMO_USERS="${SEED_DEMO_USERS:-false}"
export LOCALPG_MODE="${LOCALPG_MODE:-managed}"
# SYSTEM_DB_*(compose 约定)→ CONTEXT_DB_*(config.Load 宿主读取约定)
export CONTEXT_DB_HOST="${CONTEXT_DB_HOST:-127.0.0.1}"
export CONTEXT_DB_PORT="${CONTEXT_DB_PORT:-${SYSTEM_DB_PUBLISH_PORT:-5434}}"
export CONTEXT_DB_USER="${CONTEXT_DB_USER:-${SYSTEM_DB_USER:-app}}"
export CONTEXT_DB_PASSWORD="${CONTEXT_DB_PASSWORD:-${SYSTEM_DB_PASSWORD:?SYSTEM_DB_PASSWORD required}}"
export CONTEXT_DB_NAME="${CONTEXT_DB_NAME:-${SYSTEM_DB_NAME:-agent_system_$ENV_NAME}}"
PI_PORT="${PI_AGENT_RUNNER_PORT:-18866}"
export PI_AGENT_RUNNER_URL="${PI_AGENT_RUNNER_URL:-http://127.0.0.1:$PI_PORT}"
# 与 compose 对齐的 vault 状态根(FAV 关闭时 inert;无 master key 时 health 同样报 disconnected)
export VAULT_STATE_ROOT="${VAULT_STATE_ROOT:-$ROOT/data/vault/$ENV_NAME}"
export VAULT_STORAGE_IDENTITY="${VAULT_STORAGE_IDENTITY:-${ENV_NAME}-vault}"
BIN="${BIN_OVERRIDE:-$ROOT/bin/agent-server-$ENV_NAME}"
wait_http() {
local url="$1" retries="${2:-30}" i
for ((i = 0; i < retries; i++)); do
curl -sf -m 2 "$url" >/dev/null 2>&1 && return 0
sleep 1
done
return 1
}
stop_pid_on_port() {
local port="$1" pid
pid="$(lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | head -n1 || true)"
if [[ -n "$pid" ]]; then
act "停止占用 :$port 的进程 PID $pid"
kill "$pid" 2>/dev/null || true
for ((i = 0; i < 10; i++)); do
lsof -nP -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1 || return 0
sleep 1
done
lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | xargs -r kill -9 2>/dev/null || true
fi
}
info "环境: $ENV_NAME(HTTP :$HTTP_HOST:$HTTP_PORT / DB :$CONTEXT_DB_PORT/$CONTEXT_DB_NAME / PI :$PI_PORT / DATA_DIR=$DATA_DIR)"
# ---------- PI sidecar ----------
info "检测 PI sidecar :$PI_PORT ..."
if wait_http "http://127.0.0.1:$PI_PORT/health" 2; then
skip "PI sidecar 已健康"
else
stop_pid_on_port "$PI_PORT"
act "启动 PI sidecar(日志 $LOG_DIR/pi-sidecar-$ENV_NAME.log)..."
(
export PORT="$PI_PORT"
export DATA_DIR="$DATA_DIR/workspaces"
export PI_CODING_AGENT_DIR="$DATA_DIR/pi-agent"
nohup bash "$ROOT/deploy/pi-agent-sidecar/start.sh" >"$LOG_DIR/pi-sidecar-$ENV_NAME.log" 2>&1 &
)
if wait_http "http://127.0.0.1:$PI_PORT/health" 60; then
ok "PI sidecar 就绪"
else
fail "PI sidecar 健康检查超时,见 $LOG_DIR/pi-sidecar-$ENV_NAME.log"
exit 1
fi
fi
# ---------- agent-server ----------
if [[ "$DO_BUILD" -eq 1 ]]; then
act "从当前工作树构建 $BIN ..."
OUT_BIN="$BIN" bash "$ROOT/scripts/build-single-binary.sh" || { fail "构建失败"; exit 1; }
fi
if [[ ! -x "$BIN" ]]; then
fail "二进制不存在或不可执行: $BIN(用 --bin 指定 rc tag 构建的制品,或 --build)"
exit 1
fi
stop_pid_on_port "$HTTP_PORT"
act "后台启动 agent-server(LOCALPG_MODE=$LOCALPG_MODE,日志 $LOG_DIR/server-$ENV_NAME.log)..."
(
cd "$ROOT"
nohup "$BIN" >"$LOG_DIR/server-$ENV_NAME.log" 2>&1 &
)
if wait_http "http://127.0.0.1:$HTTP_PORT/api/v1/health" 120; then
ok "后端已启动并通过健康检查"
else
fail "后端健康检查超时,见 $LOG_DIR/server-$ENV_NAME.log"
exit 1
fi
info "完成。入口: http://127.0.0.1:$HTTP_PORT PI: http://127.0.0.1:$PI_PORT"
info "若首次从容器切换,请先跑: ./scripts/migrate-test-db.sh(test),容器 volume 保留可回滚"