# 生产服务器 Java 后端启动脚本实施记录

## 保存路径确认

- 本次新增生产服务器后端启停脚本，实施记录保存到 `docs/reports/implementation/`，符合仓库实施文档目录规范。

## 修改目标

- 新写一个可在生产服务器上运行的 Java 后端启停脚本。
- 脚本支持配置 Java Home，不依赖 Maven，不执行本地构建，只负责运行已上传到服务器的 `ruoyi-admin.jar`。

## 修改内容

- 新增 `deploy/start-java-backend-prod.sh`
  - 在脚本顶部新增“生产配置区”，生产服务器上的 Java Home、Jar 目录、Profile、JVM 参数和额外应用参数均直接写在脚本文件中。
  - 按生产服务器目录结构调整默认 Jar 路径：启动脚本位于外层目录，后端 Jar 位于 `backend/ruoyi-admin.jar`。
  - 通过脚本内 `APP_HOME="${SCRIPT_DIR}/backend"` 指定生产服务器上的 Jar 所在目录。
  - 通过脚本内 `BACKEND_JAVA_HOME` 指定脚本使用的 JDK，优先级高于系统 `JAVA_HOME`。
  - 脚本内 `BACKEND_JAVA_HOME` 留空时读取系统 `JAVA_HOME`；两者都未配置时使用 `PATH` 中的 `java`。
  - 支持 `start`、`stop`、`restart`、`status`、`logs` 操作。
  - `start` 会先调用 `stop_backend`，通过 `ps -ef` 关闭旧后端进程，再启动新的 `backend/ruoyi-admin.jar`。
  - `start` 和 `restart` 在后端启动成功后会自动持续输出 `backend/logs/backend-console.log`，按 `Ctrl+C` 仅退出日志查看，不停止后端进程。
  - 支持 `stop` 单独停止后端进程。
  - 使用 `APP_MARKER` 标记脚本启动的新进程，停止旧进程时统一通过 `ps -ef` 扫描进程列表，匹配当前 Jar 绝对路径或生产目录下的相对路径 `backend/ruoyi-admin.jar`。
  - `stop` 可停止没有脚本标记但由同一 `backend/ruoyi-admin.jar` 启动的旧进程，用于覆盖生产服务器已有手工启动进程。
  - 进程扫描会忽略 `<defunct>` 行，避免僵尸进程或历史残留干扰启停判断。
  - 若 `ps -ef` 执行失败，脚本会明确报错并中止旧进程扫描，避免误判为“后端未运行”。
  - 默认 Spring Profile 为 `uat`，可通过 `SPRING_PROFILES_ACTIVE` 覆盖。

## 使用方式

将 `deploy/start-java-backend-prod.sh` 放到生产服务器，并先修改脚本顶部“生产配置区”：

```bash
BACKEND_JAVA_HOME=""
APP_HOME="${SCRIPT_DIR}/backend"
JAR_NAME="ruoyi-admin.jar"
SPRING_PROFILES_ACTIVE="uat"
JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
APP_ARGS=""
```

配置完成后直接执行：

常用命令：

```bash
./start-java-backend-prod.sh start
./start-java-backend-prod.sh stop
./start-java-backend-prod.sh restart
./start-java-backend-prod.sh status
./start-java-backend-prod.sh logs
```

## 验证记录

- 执行 `bash -n deploy/start-java-backend-prod.sh`
  - 结果：通过
  - 说明：脚本 Bash 语法正确。
- 执行 `bash deploy/start-java-backend-prod.sh help`
  - 结果：通过
  - 说明：帮助信息正常输出，并说明启动成功后会持续输出控制台日志。
- 执行 `rg -n "start_backend|follow_logs" deploy/start-java-backend-prod.sh`
  - 结果：通过
  - 说明：已确认 `start` 与 `restart` 分支均使用 `start_action`，流程为先 `stop_backend`，再 `start_backend`，最后 `follow_logs`。
- 执行 `bash deploy/start-java-backend-prod.sh status`
  - 结果：通过
  - 说明：在允许执行 `ps -ef` 后，无后端进程时可正常输出未运行状态。
- 执行 `rg -n "pgrep" deploy/start-java-backend-prod.sh`
  - 结果：无匹配
  - 说明：已确认停止旧进程不再依赖 `pgrep`。
- 执行 `rg -n "ps -ef" deploy/start-java-backend-prod.sh`
  - 结果：通过
  - 说明：已确认旧进程扫描逻辑使用 `ps -ef`。
- 使用临时脚本副本和临时后端目录启动一个命令行包含 `-jar backend/ruoyi-admin.jar`、但不带脚本标记的模拟旧进程，再执行 `bash /tmp/start-java-backend-prod-test.sh stop`
  - 结果：通过
  - 说明：已验证 `stop` 可以停止同一 Jar 路径的旧进程，不要求旧进程必须由当前脚本启动。
- 修改临时脚本副本，将脚本内 `BACKEND_JAVA_HOME` 设置为 `/not-exist` 后执行 `bash /tmp/start-java-backend-prod-test.sh start`
  - 结果：按预期失败
  - 说明：脚本能在启动前拦截无效 Java Home，并输出明确错误。
- 执行 `bash deploy/start-java-backend-prod.sh start`
  - 结果：按预期失败
  - 说明：脚本能正确解析当前 Java 命令，并在当前本地未提供 `deploy/backend/ruoyi-admin.jar` 时中止启动。

## 影响范围

- 仅新增生产服务器后端启停脚本与本实施记录。
- 不修改 Java 业务代码、数据库脚本、前端页面和现有发布包生成脚本。
