新增后端一键重启脚本
This commit is contained in:
214
bin/restart_java_backend.sh
Executable file
214
bin/restart_java_backend.sh
Executable file
@@ -0,0 +1,214 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
|
||||
LOG_DIR="$ROOT_DIR/logs"
|
||||
CONSOLE_LOG="$LOG_DIR/backend-console.log"
|
||||
PID_FILE="$LOG_DIR/backend-spring-boot-run.pid"
|
||||
SERVER_PORT=62318
|
||||
STOP_WAIT_SECONDS=30
|
||||
APP_KEYWORD="com.ruoyi.RuoYiApplication"
|
||||
SPRING_BOOT_JVM_ARGS="-Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
|
||||
|
||||
timestamp() {
|
||||
date "+%Y-%m-%d %H:%M:%S"
|
||||
}
|
||||
|
||||
log_info() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1" >&2
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法: ./bin/restart_java_backend.sh [start|stop|restart|status]
|
||||
|
||||
默认动作:
|
||||
restart 重新构建后端并重启,随后持续输出运行日志
|
||||
EOF
|
||||
}
|
||||
|
||||
ensure_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
log_error "缺少命令: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
collect_pids() {
|
||||
all_pids=""
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
file_pid=$(cat "$PID_FILE" 2>/dev/null || true)
|
||||
if [ -n "${file_pid:-}" ] && kill -0 "$file_pid" 2>/dev/null; then
|
||||
all_pids="$all_pids $file_pid"
|
||||
fi
|
||||
fi
|
||||
|
||||
port_pids=$(lsof -tiTCP:"$SERVER_PORT" -sTCP:LISTEN 2>/dev/null || true)
|
||||
if [ -n "${port_pids:-}" ]; then
|
||||
all_pids="$all_pids $port_pids"
|
||||
fi
|
||||
|
||||
app_pids=$(pgrep -f "$APP_KEYWORD" 2>/dev/null || true)
|
||||
if [ -n "${app_pids:-}" ]; then
|
||||
all_pids="$all_pids $app_pids"
|
||||
fi
|
||||
|
||||
unique_pids=""
|
||||
for pid in $all_pids; do
|
||||
case " $unique_pids " in
|
||||
*" $pid "*) ;;
|
||||
*)
|
||||
unique_pids="$unique_pids $pid"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
printf '%s\n' "$(echo "$unique_pids" | xargs 2>/dev/null || true)"
|
||||
}
|
||||
|
||||
build_backend() {
|
||||
log_info "开始构建后端: mvn -pl ruoyi-admin -am clean package -DskipTests"
|
||||
(
|
||||
cd "$ROOT_DIR"
|
||||
mvn -pl ruoyi-admin -am clean package -DskipTests
|
||||
)
|
||||
}
|
||||
|
||||
stop_backend() {
|
||||
pids=$(collect_pids)
|
||||
|
||||
if [ -z "${pids:-}" ]; then
|
||||
log_info "未发现运行中的后端进程"
|
||||
rm -f "$PID_FILE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "准备停止后端进程: $pids"
|
||||
for pid in $pids; do
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
done
|
||||
|
||||
remaining_pids="$pids"
|
||||
elapsed=0
|
||||
while [ -n "${remaining_pids:-}" ] && [ "$elapsed" -lt "$STOP_WAIT_SECONDS" ]; do
|
||||
sleep 1
|
||||
elapsed=$((elapsed + 1))
|
||||
remaining_pids=""
|
||||
for pid in $pids; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
remaining_pids="$remaining_pids $pid"
|
||||
fi
|
||||
done
|
||||
remaining_pids=$(echo "$remaining_pids" | xargs 2>/dev/null || true)
|
||||
done
|
||||
|
||||
if [ -n "${remaining_pids:-}" ]; then
|
||||
log_info "仍有进程未退出,执行强制停止: $remaining_pids"
|
||||
for pid in $remaining_pids; do
|
||||
kill -KILL "$pid" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
rm -f "$PID_FILE"
|
||||
log_info "后端停止完成"
|
||||
}
|
||||
|
||||
start_backend() {
|
||||
mkdir -p "$LOG_DIR"
|
||||
touch "$CONSOLE_LOG"
|
||||
|
||||
printf '\n===== %s restart =====\n' "$(timestamp)" >> "$CONSOLE_LOG"
|
||||
|
||||
log_info "开始启动后端,控制台日志输出到: $CONSOLE_LOG"
|
||||
(
|
||||
cd "$ROOT_DIR/ruoyi-admin"
|
||||
nohup mvn -DskipTests \
|
||||
-Dspring-boot.run.jvmArguments="$SPRING_BOOT_JVM_ARGS" \
|
||||
spring-boot:run >> "$CONSOLE_LOG" 2>&1 &
|
||||
echo $! > "$PID_FILE"
|
||||
)
|
||||
|
||||
sleep 3
|
||||
|
||||
starter_pid=$(cat "$PID_FILE" 2>/dev/null || true)
|
||||
if [ -z "${starter_pid:-}" ] || ! kill -0 "$starter_pid" 2>/dev/null; then
|
||||
log_error "启动命令未保持运行,请检查日志: $CONSOLE_LOG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "启动命令已提交,PID: $starter_pid"
|
||||
}
|
||||
|
||||
status_backend() {
|
||||
pids=$(collect_pids)
|
||||
if [ -n "${pids:-}" ]; then
|
||||
log_info "后端正在运行,进程: $pids"
|
||||
else
|
||||
log_info "后端未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
follow_logs() {
|
||||
mkdir -p "$LOG_DIR"
|
||||
touch "$CONSOLE_LOG"
|
||||
log_info "持续输出日志中,按 Ctrl+C 仅退出日志查看"
|
||||
tail -n 200 -F "$CONSOLE_LOG"
|
||||
}
|
||||
|
||||
start_action() {
|
||||
running_pids=$(collect_pids)
|
||||
if [ -n "${running_pids:-}" ]; then
|
||||
log_error "检测到已有后端进程在运行: $running_pids,请先执行 stop 或 restart"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
build_backend
|
||||
start_backend
|
||||
follow_logs
|
||||
}
|
||||
|
||||
restart_action() {
|
||||
build_backend
|
||||
stop_backend
|
||||
start_backend
|
||||
follow_logs
|
||||
}
|
||||
|
||||
main() {
|
||||
ensure_command mvn
|
||||
ensure_command lsof
|
||||
ensure_command pgrep
|
||||
ensure_command tail
|
||||
|
||||
action="${1:-restart}"
|
||||
case "$action" in
|
||||
start)
|
||||
start_action
|
||||
;;
|
||||
stop)
|
||||
stop_backend
|
||||
;;
|
||||
restart)
|
||||
restart_action
|
||||
;;
|
||||
status)
|
||||
status_backend
|
||||
;;
|
||||
-h|--help|help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,42 @@
|
||||
# Java后端一键重启脚本实施记录
|
||||
|
||||
## 修改目标
|
||||
|
||||
- 新增一个可直接在仓库内执行的后端重启脚本
|
||||
- 脚本需支持重启前自动执行 `mvn -pl ruoyi-admin -am clean package -DskipTests`
|
||||
- 重启完成后持续输出后端运行日志,便于直接观察启动结果和后续日志
|
||||
|
||||
## 修改内容
|
||||
|
||||
- 新增 `bin/restart_java_backend.sh`
|
||||
- 默认执行 `restart` 动作,无参即可触发一键重启
|
||||
- 重启流程固定为“先构建,后停机,再启动”
|
||||
- 停机时同时兼容端口 `62318` 和 `com.ruoyi.RuoYiApplication` 关键字识别,覆盖 `jar`、IDE、`spring-boot:run` 等常见启动方式
|
||||
- 启动时改为切换到 `ruoyi-admin/` 目录后后台执行 `mvn -DskipTests spring-boot:run`
|
||||
- 启动日志统一落到仓库根目录 `logs/backend-console.log`
|
||||
- 启动后以前台 `tail -F` 持续输出控制台日志,便于直接查看
|
||||
- 保留 `start`、`stop`、`restart`、`status` 四个动作,便于和现有 `ry.sh` 使用习惯保持一致
|
||||
- 新增 `docs/tests/scripts/test-restart-java-backend.sh`
|
||||
- 回归检查 `spring-boot:run` 是否在 `ruoyi-admin` 模块目录执行
|
||||
- 防止再次误从根聚合工程触发,导致 `Unable to find a suitable main class`
|
||||
|
||||
## 验证记录
|
||||
|
||||
- 执行 `sh docs/tests/scripts/test-restart-java-backend.sh`
|
||||
- 结果:通过,已校验 `spring-boot:run` 在 `ruoyi-admin` 模块目录执行
|
||||
- 执行 `sh -n bin/restart_java_backend.sh`
|
||||
- 结果:通过,脚本语法正确
|
||||
- 执行 `sh bin/restart_java_backend.sh restart`
|
||||
- 结果:通过,构建完成后在 `ruoyi-admin` 模块内触发 `spring-boot:run`
|
||||
- 关键日志:
|
||||
- `Building ruoyi-admin 3.9.1`
|
||||
- `Starting RuoYiApplication`
|
||||
- `Started RuoYiApplication`
|
||||
- 执行 `sh bin/restart_java_backend.sh stop`
|
||||
- 结果:测试完成后已停止本次验证拉起的后端进程,避免残留端口占用
|
||||
|
||||
## 影响范围
|
||||
|
||||
- 新增本地运维辅助脚本,不修改现有 Java 业务代码
|
||||
- 日志新增输出文件:`logs/backend-console.log`
|
||||
- 不影响前端、数据库和 Mock 服务逻辑
|
||||
30
docs/tests/scripts/test-restart-java-backend.sh
Normal file
30
docs/tests/scripts/test-restart-java-backend.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/../../.." && pwd)
|
||||
SCRIPT_FILE="$ROOT_DIR/bin/restart_java_backend.sh"
|
||||
|
||||
echo "[检查] spring-boot:run 必须在 ruoyi-admin 模块目录执行"
|
||||
|
||||
if ! grep -Fq 'cd "$ROOT_DIR/ruoyi-admin"' "$SCRIPT_FILE"; then
|
||||
echo "失败: 未切换到 ruoyi-admin 模块目录"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -Fq 'nohup mvn -pl ruoyi-admin -am -DskipTests' "$SCRIPT_FILE"; then
|
||||
echo "失败: 仍在根工程直接执行 spring-boot:run"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq 'nohup mvn -DskipTests' "$SCRIPT_FILE"; then
|
||||
echo "失败: 未使用模块内 mvn -DskipTests spring-boot:run"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq 'spring-boot:run >> "$CONSOLE_LOG" 2>&1 &' "$SCRIPT_FILE"; then
|
||||
echo "失败: 未找到 spring-boot:run 后台启动命令"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "通过"
|
||||
Reference in New Issue
Block a user