Files
senmesh-zc/backend/scripts/sfile-ctl.sh

210 lines
7.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# ==============================================================================
# s-file 一键部署/运维脚本(生产环境)
#
# 用法:
# ./sfile-ctl.sh start 启动服务
# ./sfile-ctl.sh stop 停止服务
# ./sfile-ctl.sh restart 重启服务
# ./sfile-ctl.sh status 查看状态
# ./sfile-ctl.sh deploy <jar路径> 发布新版 jar(自动备份旧版并重启)
# ./sfile-ctl.sh log [行数] 查看启动日志(默认 200 行)
# ./sfile-ctl.sh db-upgrade <sql路径> 在达梦库执行升级 SQL(需配置 disql)
# 上线用: db/upgrade-20260915-release.sql
#
# 部署目录结构(脚本首次 start 时自动创建,配置需手工放置):
# /opt/sfile/
# ├── s-file.jar 服务 jar
# ├── config/application.yml 生产配置(模板见 docs/生产部署说明.md)
# ├── backup/ 历史版本备份
# ├── logs/ 日志目录
# └── data/ 上传/摆渡目录(upload/transfer/send/transfer/receive)
# ==============================================================================
set -euo pipefail
# ------------------------- 环境变量(按服务器实际修改) -------------------------
APP_NAME="s-file"
INSTALL_DIR="${SFILE_INSTALL_DIR:-/opt/sfile}"
JAR_FILE="${INSTALL_DIR}/${APP_NAME}.jar"
CONFIG_FILE="${INSTALL_DIR}/config/application.yml"
LOG_DIR="${INSTALL_DIR}/logs"
BACKUP_DIR="${INSTALL_DIR}/backup"
STDOUT_LOG="${LOG_DIR}/stdout.log"
GC_LOG="${LOG_DIR}/gc.log"
# 运行用户(root 部署时可改为专用低权用户,如 sfile)
RUN_USER="${SFILE_RUN_USER:-$(whoami)}"
# JVM 参数:按机器内存调整 -Xmx;生产建议 2g 起
JAVA_OPTS="${SFILE_JAVA_OPTS:--Xms1g -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOG_DIR} -Xloggc:${GC_LOG} -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M}"
# 健康检查地址与超时
HEALTH_URL="http://127.0.0.1:8080/user/info"
START_TIMEOUT=120
# 达梦 disql(db-upgrade 用;达梦容器则为 docker exec -i <容器> /opt/dmdbms/bin/disql ...)
DISQL_CMD="${SFILE_DISQL:-disql <DB_USER>/<DB_PASSWORD>@<DB_HOST>:5236}"
# -----------------------------------------------------------------------------
GREEN='\033[32m'; RED='\033[31m'; YELLOW='\033[33m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
err() { echo -e "${RED}[ERROR]${NC} $*"; }
get_pid() {
pgrep -f "java .*${JAR_FILE}" 2>/dev/null || true
}
require_env() {
[ -f "${JAR_FILE}" ] || { err "jar 不存在: ${JAR_FILE},先用 deploy 发布"; exit 1; }
[ -f "${CONFIG_FILE}" ] || { err "配置不存在: ${CONFIG_FILE}(模板见 docs/生产部署说明.md)"; exit 1; }
# 项目要求 JDK 8 运行(字节码 52.0),防护误用高版本 JDK
if command -v java >/dev/null 2>&1; then
local major
major=$(java -version 2>&1 | head -1 | sed -E 's/.*"([0-9]+)\..*"/\1/')
if [ "${major}" != "1" ] && [ "${major}" != "8" ]; then
err "检测到 java 版本为 ${major},本项目要求 JDK 8(请 export JAVA_HOME 指向 JDK8 并确认 java 命令)"
exit 1
fi
else
err "未找到 java 命令,请安装 JDK 8 并配置 PATH"; exit 1
fi
}
prepare_dirs() {
mkdir -p "${INSTALL_DIR}/config" "${LOG_DIR}" "${BACKUP_DIR}" \
"${INSTALL_DIR}/data/upload" \
"${INSTALL_DIR}/data/transfer/send" \
"${INSTALL_DIR}/data/transfer/receive"
}
start() {
require_env
local pid
pid=$(get_pid)
if [ -n "${pid}" ]; then
warn "${APP_NAME} 已在运行 (PID ${pid}),如需重启请先 stop"
exit 0
fi
prepare_dirs
info "启动 ${APP_NAME} ..."
# workerId 说明:多节点部署时每台机器配置不同的 code.snowflake.workid.<本机IP>,
# 最简单的方式是用环境变量(. 映射为 _),如:
# export CODE_SNOWFLAKE_WORKID_192_168_1_10=1
# shellcheck disable=SC2086
if [ "${RUN_USER}" = "$(whoami)" ]; then
(cd "${INSTALL_DIR}" && nohup java ${JAVA_OPTS} \
-Dspring.config.additional-location=file:${CONFIG_FILE} \
-jar ${JAR_FILE} >> ${STDOUT_LOG} 2>&1 & echo $! > "${INSTALL_DIR}/app.pid")
else
su -s /bin/bash "${RUN_USER}" -c "cd ${INSTALL_DIR} && nohup java ${JAVA_OPTS} \
-Dspring.config.additional-location=file:${CONFIG_FILE} \
-jar ${JAR_FILE} >> ${STDOUT_LOG} 2>&1 & echo \$! > ${INSTALL_DIR}/app.pid"
fi
# 启动健康检查轮询
info "等待服务就绪(最多 ${START_TIMEOUT}s)..."
local waited=0
while [ ${waited} -lt ${START_TIMEOUT} ]; do
if curl -sf -o /dev/null --max-time 3 "${HEALTH_URL}"; then
info "启动成功 (PID $(cat "${INSTALL_DIR}/app.pid")),耗时约 ${waited}s"
info "日志: tail -f ${STDOUT_LOG}"
return 0
fi
# 进程若已退出则立即报错,不干等
if [ -z "$(get_pid)" ]; then
err "进程已退出,最近日志:"
tail -30 "${STDOUT_LOG}"
exit 1
fi
sleep 3; waited=$((waited + 3))
done
err "${START_TIMEOUT}s 内未就绪,请检查日志: tail -100 ${STDOUT_LOG}"
exit 1
}
stop() {
local pid
pid=$(get_pid)
if [ -z "${pid}" ]; then
info "${APP_NAME} 未在运行"
return 0
fi
info "停止 ${APP_NAME} (PID ${pid}) ..."
kill "${pid}"
local waited=0
while kill -0 "${pid}" 2>/dev/null && [ ${waited} -lt 60 ]; do
sleep 2; waited=$((waited + 2))
done
if kill -0 "${pid}" 2>/dev/null; then
warn "60s 未退出,强制 kill -9"
kill -9 "${pid}" 2>/dev/null || true
fi
rm -f "${INSTALL_DIR}/app.pid"
info "已停止"
}
status() {
local pid
pid=$(get_pid)
if [ -z "${pid}" ]; then
info "${APP_NAME}: 未运行"
exit 1
fi
info "${APP_NAME}: 运行中 (PID ${pid})"
if curl -sf -o /dev/null --max-time 3 "${HEALTH_URL}"; then
info "健康检查: 正常"
else
warn "健康检查: 8080 未响应(可能仍在启动)"
fi
info "内存: $(ps -o rss= -p "${pid}" | awk '{printf "%.0fMB", $1/1024}')"
}
deploy() {
local new_jar="$1"
[ -f "${new_jar}" ] || { err "找不到 jar: ${new_jar}"; exit 1; }
prepare_dirs
local ts; ts=$(date +%Y%m%d-%H%M%S)
if [ -f "${JAR_FILE}" ]; then
# 运行中先停
if [ -n "$(get_pid)" ]; then
stop
fi
cp "${JAR_FILE}" "${BACKUP_DIR}/${APP_NAME}-${ts}.jar"
info "旧版本已备份: ${BACKUP_DIR}/${APP_NAME}-${ts}.jar"
fi
cp "${new_jar}" "${JAR_FILE}"
# 保留最近 5 个备份
ls -1t "${BACKUP_DIR}/${APP_NAME}-"*.jar 2>/dev/null | tail -n +6 | xargs -r rm -f
info "新版本已就位: ${JAR_FILE} ($(du -h "${JAR_FILE}" | cut -f1))"
start
}
db_upgrade() {
local sql_file="$1"
[ -f "${sql_file}" ] || { err "找不到 SQL: ${sql_file}"; exit 1; }
case "${DISQL_CMD}" in
*"<DB_USER>"*) err "请先在脚本头部或环境变量 SFILE_DISQL 配置真实 disql 连接串"; exit 1;;
esac
info "执行升级 SQL: ${sql_file}"
# 达梦 disql 执行 SQL 文件语法: disql 用户/密码@host:port \`文件路径\`
${DISQL_CMD} \`"${sql_file}"
info "执行完成,请核对上方输出无 ERROR 后再继续部署"
}
log() {
local lines="${1:-200}"
tail -n "${lines}" "${STDOUT_LOG}" 2>/dev/null || warn "暂无日志: ${STDOUT_LOG}"
}
case "${1:-}" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
status) status ;;
deploy) [ $# -ge 2 ] || { err "用法: $0 deploy <jar路径>"; exit 1; }; deploy "$2" ;;
log) log "${2:-200}" ;;
db-upgrade) [ $# -ge 2 ] || { err "用法: $0 db-upgrade <sql路径>"; exit 1; }; db_upgrade "$2" ;;
*) sed -n '2,20p' "$0"; exit 1 ;;
esac