From c972ea485dac1d2f1a1294324fbcb78f42cf2b00 Mon Sep 17 00:00:00 2001 From: shaw Date: Wed, 6 Aug 2025 14:15:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20manage.sh=E5=9C=A8centos=E4=B8=8A?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/MANAGE_UPDATE.md | 114 --------------------- scripts/manage.sh | 212 +++++++++++++++++++++++---------------- 2 files changed, 125 insertions(+), 201 deletions(-) delete mode 100644 scripts/MANAGE_UPDATE.md diff --git a/scripts/MANAGE_UPDATE.md b/scripts/MANAGE_UPDATE.md deleted file mode 100644 index cfcc8fa2..00000000 --- a/scripts/MANAGE_UPDATE.md +++ /dev/null @@ -1,114 +0,0 @@ -# manage.sh 脚本更新说明 - -## 新增功能(最新更新) - -### 1. 端口配置 -- 安装时会询问服务端口,默认为 3000 -- 端口配置会自动写入 .env 文件 -- 检查端口是否被占用并提示 - -### 2. 自动启动服务 -- 安装完成后自动启动服务 -- 不再需要手动执行 `crs start` - -### 3. 公网 IP 显示 -- 自动获取公网 IP 地址(通过 https://ipinfo.io/json) -- 显示本地访问和公网访问地址 -- IP 地址缓存 1 小时,避免频繁调用 API - -### 4. 动态端口显示 -- 所有状态显示都使用实际配置的端口 -- 交互式菜单显示实际端口和公网地址 - -## 使用示例 - -### 安装时的新体验 -```bash -$ crs install - -# 会依次询问: -安装目录 (默认: ~/claude-relay-service): -服务端口 (默认: 3000): 8080 -Redis 地址 (默认: localhost): -Redis 端口 (默认: 6379): -Redis 密码 (默认: 无密码): - -# 安装完成后自动启动并显示: -服务已成功安装并启动! - -访问地址: - 本地访问: http://localhost:8080/web - 公网访问: http://1.2.3.4:8080/web - -管理命令: - 查看状态: crs status - 停止服务: crs stop - 重启服务: crs restart -``` - -### 状态显示增强 -```bash -$ crs status - -=== Claude Relay Service 状态 === -服务状态: 运行中 -进程 PID: 12345 -服务端口: 8080 - -访问地址: - 本地访问: http://localhost:8080/web - 公网访问: http://1.2.3.4:8080/web - API 端点: http://localhost:8080/api/v1 - -安装目录: /home/user/claude-relay-service - -Redis 状态: - 连接状态: 正常 -``` - -## 技术细节 - -### 公网 IP 获取 -- 主要 API: https://ipinfo.io/json -- 备用 API: https://api.ipify.org -- 缓存文件: /tmp/.crs_public_ip_cache -- 缓存时间: 3600 秒(1 小时) - -### 端口配置存储 -- 配置文件: .env -- 环境变量: PORT -- 读取优先级: 命令行参数 > .env 文件 > 默认值 3000 - -## Redis 安装说明 - -### 系统默认安装位置 -脚本使用系统包管理器安装 Redis,会自动安装到各系统的默认位置: - -- **Debian/Ubuntu**: - - 配置文件: `/etc/redis/redis.conf` - - 数据目录: `/var/lib/redis` - - 日志文件: `/var/log/redis/redis-server.log` - - 通过 systemd 管理: `systemctl status redis-server` - -- **RedHat/CentOS**: - - 配置文件: `/etc/redis.conf` - - 数据目录: `/var/lib/redis` - - 日志文件: `/var/log/redis/redis.log` - - 通过 systemd 管理: `systemctl status redis` - -- **Arch Linux**: - - 配置文件: `/etc/redis/redis.conf` - - 数据目录: `/var/lib/redis` - - 通过 systemd 管理: `systemctl status redis` - -- **macOS**: - - 通过 Homebrew 安装 - - 配置文件: `/usr/local/etc/redis.conf` - - 数据目录: `/usr/local/var/db/redis/` - - 通过 brew services 管理: `brew services list` - -### 优势 -- Redis 数据独立于应用,卸载应用不会丢失数据 -- 使用系统标准服务管理 -- 自动开机启动 -- 系统级的日志和监控 \ No newline at end of file diff --git a/scripts/manage.sh b/scripts/manage.sh index 320846b5..ebd41b3a 100644 --- a/scripts/manage.sh +++ b/scripts/manage.sh @@ -516,11 +516,6 @@ EOF fi fi - # 创建systemd服务文件(Linux) - if [[ "$OS" == "debian" || "$OS" == "redhat" || "$OS" == "arch" ]]; then - create_systemd_service - fi - # 创建软链接 create_symlink @@ -553,38 +548,6 @@ EOF echo " 重启服务: crs restart" } -# 创建systemd服务 -create_systemd_service() { - local service_file="/etc/systemd/system/claude-relay.service" - - print_info "创建 systemd 服务..." - - sudo tee $service_file > /dev/null << EOF -[Unit] -Description=Claude Relay Service -After=network.target redis.service - -[Service] -Type=simple -User=$USER -WorkingDirectory=$APP_DIR -Environment="NODE_ENV=production" -EnvironmentFile=-$APP_DIR/.env -ExecStart=$(which node) $APP_DIR/src/app.js -Restart=on-failure -RestartSec=10 -StandardOutput=append:$APP_DIR/logs/service.log -StandardError=append:$APP_DIR/logs/service-error.log -# 确保日志目录存在 -ExecStartPre=/bin/mkdir -p $APP_DIR/logs - -[Install] -WantedBy=multi-user.target -EOF - - sudo systemctl daemon-reload - print_success "systemd 服务创建完成" -} # 更新服务 update_service() { @@ -597,17 +560,39 @@ update_service() { cd "$APP_DIR" - # 停止服务 - stop_service + # 保存当前运行状态 + local was_running=false + if pgrep -f "node.*src/app.js" > /dev/null; then + was_running=true + print_info "检测到服务正在运行,将在更新后自动重启..." + stop_service + fi + + # 备份配置文件 + print_info "备份配置文件..." + if [ -f ".env" ]; then + cp .env .env.backup.$(date +%Y%m%d%H%M%S) + fi + if [ -f "config/config.js" ]; then + cp config/config.js config/config.js.backup.$(date +%Y%m%d%H%M%S) + fi # 拉取最新代码 print_info "拉取最新代码..." - git pull origin main + if ! git pull origin main; then + print_error "拉取代码失败,请检查网络连接" + return 1 + fi # 更新依赖 print_info "更新依赖..." npm install + # 确保脚本有执行权限 + if [ -f "$APP_DIR/scripts/manage.sh" ]; then + chmod +x "$APP_DIR/scripts/manage.sh" + fi + # 获取最新的预构建前端文件 print_info "更新前端文件..." @@ -667,10 +652,21 @@ update_service() { fi fi - # 启动服务 - start_service + # 更新软链接到最新版本 + create_symlink + + # 如果之前在运行,则重新启动服务 + if [ "$was_running" = true ]; then + print_info "重新启动服务..." + start_service + fi print_success "更新完成!" + + # 显示版本信息 + if [ -f "$APP_DIR/VERSION" ]; then + echo -e "\n当前版本: ${GREEN}$(cat "$APP_DIR/VERSION")${NC}" + fi } # 卸载服务 @@ -699,13 +695,6 @@ uninstall_service() { # 停止服务 stop_service - # 删除systemd服务 - if [ -f "/etc/systemd/system/claude-relay.service" ]; then - sudo systemctl disable claude-relay.service - sudo rm /etc/systemd/system/claude-relay.service - sudo systemctl daemon-reload - fi - # 备份数据 echo -n "是否备份数据?(y/N): " read -n 1 backup @@ -746,58 +735,101 @@ start_service() { cd "$APP_DIR" # 检查是否已运行 - if pgrep -f "node.*claude-relay" > /dev/null; then + if pgrep -f "node.*src/app.js" > /dev/null; then print_warning "服务已在运行" return 0 fi - # 使用不同方式启动 - if [ -f "/etc/systemd/system/claude-relay.service" ]; then - # 先重新加载systemd配置 - sudo systemctl daemon-reload + # 确保日志目录存在 + mkdir -p "$APP_DIR/logs" + + # 检查pm2是否可用并且不是从package.json脚本调用的 + if command_exists pm2 && [ "$1" != "--no-pm2" ]; then + print_info "使用 pm2 启动服务..." + # 直接使用pm2启动,避免循环调用 + pm2 start "$APP_DIR/src/app.js" --name "claude-relay" --log "$APP_DIR/logs/pm2.log" 2>/dev/null + sleep 2 - # 启动服务 - sudo systemctl start claude-relay.service - - # 等待服务启动 - sleep 3 - - # 检查服务状态 - if sudo systemctl is-active claude-relay.service >/dev/null 2>&1; then - print_success "服务已通过 systemd 启动" + # 检查是否启动成功 + if pm2 list 2>/dev/null | grep -q "claude-relay"; then + print_success "服务已通过 pm2 启动" + pm2 save 2>/dev/null || true else - print_warning "systemd 启动失败,尝试使用 npm 启动..." - # 查看失败原因 - sudo journalctl -u claude-relay.service -n 20 --no-pager 2>/dev/null - - # 尝试使用npm启动 - npm run service:start:daemon - print_success "服务已通过 npm 启动" + print_warning "pm2 启动失败,尝试直接启动..." + start_service_direct fi else - # 使用npm启动 - npm run service:start:daemon - print_success "服务已启动" + start_service_direct fi sleep 2 - show_status + + # 验证服务是否成功启动 + if pgrep -f "node.*src/app.js" > /dev/null; then + show_status + else + print_error "服务启动失败,请查看日志: $APP_DIR/logs/service.log" + if [ -f "$APP_DIR/logs/service.log" ]; then + echo "最近的错误日志:" + tail -n 20 "$APP_DIR/logs/service.log" + fi + return 1 + fi +} + +# 直接启动服务(不使用pm2) +start_service_direct() { + print_info "使用后台进程启动服务..." + + # 使用setsid创建新会话,确保进程完全脱离终端 + if command_exists setsid; then + # setsid方式(推荐) + setsid nohup node "$APP_DIR/src/app.js" > "$APP_DIR/logs/service.log" 2>&1 < /dev/null & + local pid=$! + sleep 1 + + # 获取实际的子进程PID + local real_pid=$(pgrep -f "node.*src/app.js" | head -1) + if [ -n "$real_pid" ]; then + echo $real_pid > "$APP_DIR/.pid" + print_success "服务已在后台启动 (PID: $real_pid)" + else + echo $pid > "$APP_DIR/.pid" + print_success "服务已在后台启动 (PID: $pid)" + fi + else + # 备用方式:使用nohup和disown + nohup node "$APP_DIR/src/app.js" > "$APP_DIR/logs/service.log" 2>&1 < /dev/null & + local pid=$! + disown $pid 2>/dev/null || true + echo $pid > "$APP_DIR/.pid" + print_success "服务已在后台启动 (PID: $pid)" + fi } # 停止服务 stop_service() { print_info "停止服务..." - if [ -f "/etc/systemd/system/claude-relay.service" ]; then - sudo systemctl stop claude-relay.service - else - if command_exists pm2; then - cd "$APP_DIR" 2>/dev/null && npm run service:stop - else - pkill -f "node.*claude-relay" || true + # 尝试使用pm2停止 + if command_exists pm2 && [ -n "$APP_DIR" ] && [ -d "$APP_DIR" ]; then + cd "$APP_DIR" 2>/dev/null + pm2 stop claude-relay 2>/dev/null || true + pm2 delete claude-relay 2>/dev/null || true + fi + + # 使用PID文件停止 + if [ -f "$APP_DIR/.pid" ]; then + local pid=$(cat "$APP_DIR/.pid") + if kill -0 $pid 2>/dev/null; then + kill $pid + rm -f "$APP_DIR/.pid" fi fi + # 强制停止所有相关进程 + pkill -f "node.*src/app.js" 2>/dev/null || true + print_success "服务已停止" } @@ -851,12 +883,18 @@ show_status() { actual_port=${actual_port:-3000} # 检查进程 - if pgrep -f "node.*claude-relay" > /dev/null; then + local pid=$(pgrep -f "node.*src/app.js" | head -1) + if [ -n "$pid" ]; then echo -e "服务状态: ${GREEN}运行中${NC}" - - # 获取进程信息 - local pid=$(pgrep -f "node.*claude-relay" | head -1) echo "进程 PID: $pid" + + # 显示进程信息 + if command_exists ps; then + local proc_info=$(ps -p $pid -o comm,etime,rss --no-headers 2>/dev/null) + if [ -n "$proc_info" ]; then + echo "进程信息: $proc_info" + fi + fi echo "服务端口: $actual_port" # 获取公网IP @@ -946,9 +984,9 @@ show_menu() { actual_port=${actual_port:-3000} # 检查服务状态 - if pgrep -f "node.*claude-relay" > /dev/null; then + local pid=$(pgrep -f "node.*src/app.js" | head -1) + if [ -n "$pid" ]; then echo -e " 运行状态: ${GREEN}运行中${NC}" - local pid=$(pgrep -f "node.*claude-relay" | head -1) echo -e " 进程 PID: $pid" echo -e " 服务端口: $actual_port"