#!/usr/bin/env bash set -euo pipefail # ====== 可改配置 ====== APP_NAME="xinli-server" PORT="30081" JAR_NAME="ry-xinli-admin.jar" # 改成你的实际jar文件名 APP_HOME="$(cd "$(dirname "$0")" && pwd)" JAR_PATH="${APP_HOME}/${JAR_NAME}" LOG_DIR="${APP_HOME}/logs" LOG_FILE="${LOG_DIR}/${APP_NAME}.log" PID_FILE="${APP_HOME}/${APP_NAME}.pid" JAVA_OPTS="-Xms512m -Xmx1024m -Dfile.encoding=UTF-8" SPRING_OPTS="--server.port=${PORT} --server.address=0.0.0.0" # 如果你走 Python RAG(可选) export RAG_PYTHON_URL="${RAG_PYTHON_URL:-http://127.0.0.1:5000}" # ====================== mkdir -p "${LOG_DIR}" echo "[1/4] 检查 jar 是否存在:${JAR_PATH}" if [[ ! -f "${JAR_PATH}" ]]; then echo "ERROR: jar 不存在:${JAR_PATH}" exit 1 fi kill_by_port() { local port="$1" local pids="" # 优先用 lsof if command -v lsof >/dev/null 2>&1; then pids="$(lsof -ti tcp:${port} 2>/dev/null || true)" # 再用 ss(大多数 Linux 有) elif command -v ss >/dev/null 2>&1; then # 从 ss 输出里提取 pid=xxxx pids="$(ss -lntp 2>/dev/null | awk -v p=":${port}" '$4 ~ p {print $0}' | sed -n 's/.*pid=\\([0-9]\\+\\).*/\\1/p' | sort -u)" # 再用 netstat(老系统) elif command -v netstat >/dev/null 2>&1; then pids="$(netstat -lntp 2>/dev/null | awk -v p=":${port}" '$4 ~ p {print $7}' | cut -d/ -f1 | grep -E '^[0-9]+$' | sort -u)" else echo "ERROR: 找不到 lsof/ss/netstat,无法通过端口查进程。请先安装 lsof(推荐)。" exit 1 fi if [[ -n "${pids}" ]]; then echo "[2/4] 端口 ${port} 被占用,准备杀进程:${pids}" for pid in ${pids}; do echo " - kill ${pid}" kill "${pid}" 2>/dev/null || true done # 等待退出,最多 10 秒 for _ in {1..10}; do sleep 1 local still="" if command -v lsof >/dev/null 2>&1; then still="$(lsof -ti tcp:${port} 2>/dev/null || true)" elif command -v ss >/dev/null 2>&1; then still="$(ss -lntp 2>/dev/null | awk -v p=":${port}" '$4 ~ p {print $0}' | sed -n 's/.*pid=\\([0-9]\\+\\).*/\\1/p' | sort -u)" elif command -v netstat >/dev/null 2>&1; then still="$(netstat -lntp 2>/dev/null | awk -v p=":${port}" '$4 ~ p {print $7}' | cut -d/ -f1 | grep -E '^[0-9]+$' | sort -u)" fi [[ -z "${still}" ]] && break done # 如果还占用就强杀 if command -v lsof >/dev/null 2>&1; then pids="$(lsof -ti tcp:${port} 2>/dev/null || true)" fi if [[ -n "${pids}" ]]; then echo "端口仍被占用,强制 kill -9:${pids}" for pid in ${pids}; do kill -9 "${pid}" 2>/dev/null || true done fi else echo "[2/4] 端口 ${port} 未占用" fi } stop_by_pidfile() { if [[ -f "${PID_FILE}" ]]; then local pid pid="$(cat "${PID_FILE}" || true)" if [[ -n "${pid}" ]] && kill -0 "${pid}" >/dev/null 2>&1; then echo "[2/4] 发现旧 PID_FILE:${PID_FILE} (pid=${pid}),先停止旧进程" kill "${pid}" 2>/dev/null || true sleep 2 kill -9 "${pid}" 2>/dev/null || true fi rm -f "${PID_FILE}" >/dev/null 2>&1 || true fi } echo "[2/4] 停止旧进程(先按 PID_FILE,再按端口)" stop_by_pidfile kill_by_port "${PORT}" echo "[3/4] 启动应用(日志:${LOG_FILE})" nohup java ${JAVA_OPTS} -jar "${JAR_PATH}" ${SPRING_OPTS} >> "${LOG_FILE}" 2>&1 & echo $! > "${PID_FILE}" echo "已启动:pid=$(cat "${PID_FILE}")" echo "[4/4] 等待端口 ${PORT} 监听(最多 30 秒)" for i in {1..30}; do if command -v ss >/dev/null 2>&1; then if ss -lnt | awk '{print $4}' | grep -q ":${PORT}\$"; then echo "OK:端口已监听。" echo "查看日志:tail -f ${LOG_FILE}" exit 0 fi else # 没有 ss 就不硬等,提示用户看日志 break fi sleep 1 done echo "WARN:30 秒内未检测到端口监听,请查看日志排查:${LOG_FILE}" exit 1