#!/bin/bash # 安装/卸载 macOS launchd 服务(主服务 + watchdog 健康监测) # 用法: ./deploy/install-service.sh {install|uninstall} set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" # 加载 .env if [ -f "$PROJECT_DIR/.env" ]; then set -a; source "$PROJECT_DIR/.env"; set +a fi PORT="${BACKEND_PORT:-8000}" VENV_DIR="$PROJECT_DIR/.venv" LOG_DIR="$PROJECT_DIR/logs" PLIST_APP="com.readoor.buildserver" PLIST_WD="com.readoor.buildserver.watchdog" PLIST_APP_TARGET="$HOME/Library/LaunchAgents/$PLIST_APP.plist" PLIST_WD_TARGET="$HOME/Library/LaunchAgents/$PLIST_WD.plist" do_install() { if [ ! -d "$VENV_DIR" ]; then echo "请先执行 ./deploy.sh build" exit 1 fi if [ ! -d "$PROJECT_DIR/backend/static" ]; then echo "请先执行 ./deploy.sh build" exit 1 fi mkdir -p "$LOG_DIR" # ---- 主服务 plist ---- cat > "$PLIST_APP_TARGET" < Label $PLIST_APP ProgramArguments $VENV_DIR/bin/python3 -m uvicorn backend.main:app --host 0.0.0.0 --port $PORT --workers 1 WorkingDirectory $PROJECT_DIR EnvironmentVariables PATH $VENV_DIR/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin RunAtLoad KeepAlive SuccessfulExit StandardOutPath $LOG_DIR/server-stdout.log StandardErrorPath $LOG_DIR/server-stderr.log EOF # ---- Watchdog plist ---- cat > "$PLIST_WD_TARGET" < Label $PLIST_WD ProgramArguments $PROJECT_DIR/deploy.sh _watchdog_loop WorkingDirectory $PROJECT_DIR EnvironmentVariables PATH $VENV_DIR/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin RunAtLoad KeepAlive StandardOutPath $LOG_DIR/watchdog-stdout.log StandardErrorPath $LOG_DIR/watchdog-stderr.log EOF # 加载服务 launchctl unload "$PLIST_WD_TARGET" 2>/dev/null || true launchctl unload "$PLIST_APP_TARGET" 2>/dev/null || true launchctl load "$PLIST_APP_TARGET" launchctl load "$PLIST_WD_TARGET" echo "服务已安装并启动" echo " 主服务: http://localhost:$PORT" echo " Watchdog: 每 ${WATCHDOG_INTERVAL:-30}s 健康检查,故障自动重启" echo " 日志目录: $LOG_DIR" echo "" echo "卸载命令: $0 uninstall" } do_uninstall() { if [ -f "$PLIST_WD_TARGET" ]; then launchctl unload "$PLIST_WD_TARGET" 2>/dev/null || true rm -f "$PLIST_WD_TARGET" echo "Watchdog 已卸载" fi if [ -f "$PLIST_APP_TARGET" ]; then launchctl unload "$PLIST_APP_TARGET" 2>/dev/null || true rm -f "$PLIST_APP_TARGET" echo "主服务已卸载" fi } case "${1:-}" in install) do_install ;; uninstall) do_uninstall ;; *) echo "用法: $0 {install|uninstall}" exit 1 ;; esac