124 lines
3.8 KiB
Bash
124 lines
3.8 KiB
Bash
#!/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 |