修改大屏
This commit is contained in:
374
bank-backend/node_manager.sh
Normal file
374
bank-backend/node_manager.sh
Normal file
@@ -0,0 +1,374 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Node.js 服务管理脚本 - 银行端后端(bank-backend)
|
||||
# 使用方法: ./node_manager.sh [start|stop|restart|status]
|
||||
|
||||
# 配置区域
|
||||
APP_NAME="bank-backend"
|
||||
ENTRY_FILE="server.js"
|
||||
APP_PORT="5351"
|
||||
LOG_DIR="logs"
|
||||
LOG_FILE="${LOG_DIR}/${APP_NAME}.log"
|
||||
PID_FILE="pid.${APP_NAME}"
|
||||
NODE_ENV="production"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 创建日志目录
|
||||
if [ ! -d "$LOG_DIR" ]; then
|
||||
mkdir -p "$LOG_DIR"
|
||||
echo "已创建日志目录: $LOG_DIR"
|
||||
fi
|
||||
|
||||
# 检查 Node.js 是否安装
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo -e "${RED}错误: Node.js 未安装或不在 PATH 中${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查入口文件是否存在
|
||||
if [ ! -f "$ENTRY_FILE" ]; then
|
||||
echo -e "${RED}错误: 入口文件 $ENTRY_FILE 不存在${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 显示 Node.js 版本信息
|
||||
NODE_VERSION=$(node --version)
|
||||
echo -e "${GREEN}Node.js 版本: $NODE_VERSION${NC}"
|
||||
|
||||
# 使用 PM2 启动服务(如已安装)
|
||||
function startPM2() {
|
||||
if command -v pm2 &> /dev/null; then
|
||||
echo -e "${YELLOW}检测到已安装 PM2,使用 PM2 管理服务: $APP_NAME${NC}"
|
||||
# 确保日志目录存在
|
||||
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR"
|
||||
pm2 start "$ENTRY_FILE" \
|
||||
--name "$APP_NAME" \
|
||||
--cwd "$(pwd)" \
|
||||
--env "$NODE_ENV" \
|
||||
--time \
|
||||
--output "$LOG_DIR/${APP_NAME}.out.log" \
|
||||
--error "$LOG_DIR/${APP_NAME}.err.log"
|
||||
|
||||
pm2 save
|
||||
echo -e "${GREEN}PM2 已启动并保存进程列表(pm2 save)${NC}"
|
||||
echo "如需开机自启,请执行(一次性):"
|
||||
echo "pm2 startup systemd -u $(whoami) --hp $HOME; pm2 save"
|
||||
echo "查看状态: pm2 status $APP_NAME"
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 停止服务函数
|
||||
function stopApp() {
|
||||
echo -e "${YELLOW}正在停止服务: $APP_NAME${NC}"
|
||||
|
||||
# 从 PID 文件读取进程 ID
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p $PID > /dev/null 2>&1; then
|
||||
echo "找到进程 PID: $PID,正在停止..."
|
||||
kill -TERM $PID
|
||||
|
||||
# 等待进程优雅退出
|
||||
for i in {1..10}; do
|
||||
if ! ps -p $PID > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}服务已优雅停止${NC}"
|
||||
rm -f "$PID_FILE"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# 如果优雅停止失败,强制杀死
|
||||
echo -e "${YELLOW}优雅停止失败,强制终止进程${NC}"
|
||||
kill -9 $PID
|
||||
rm -f "$PID_FILE"
|
||||
else
|
||||
echo "PID 文件存在但进程不存在,清理 PID 文件"
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
else
|
||||
# 如果没有 PID 文件,尝试通过端口查找
|
||||
PID=$(lsof -ti:$APP_PORT 2>/dev/null)
|
||||
if [ -n "$PID" ]; then
|
||||
echo "通过端口 $APP_PORT 找到 PID: $PID,正在停止..."
|
||||
kill -TERM $PID
|
||||
sleep 2
|
||||
if ps -p $PID > /dev/null 2>&1; then
|
||||
kill -9 $PID
|
||||
fi
|
||||
echo -e "${GREEN}服务已停止${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}未找到运行中的服务: $APP_NAME${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 启动服务函数
|
||||
function startApp() {
|
||||
echo -e "${YELLOW}正在启动服务: $APP_NAME${NC}"
|
||||
|
||||
# 优先使用 PM2 管理服务
|
||||
if startPM2; then
|
||||
echo -e "${GREEN}服务已通过 PM2 启动并托管,支持崩溃自动重启${NC}"
|
||||
echo "日志: $LOG_DIR/${APP_NAME}.out.log 和 $LOG_DIR/${APP_NAME}.err.log"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 检查服务是否已经运行
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p $PID > /dev/null 2>&1; then
|
||||
echo -e "${YELLOW}服务已在运行中 (PID: $PID)${NC}"
|
||||
return 0
|
||||
else
|
||||
echo "PID 文件存在但进程不存在,清理后重新启动"
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查端口是否被占用
|
||||
if command -v lsof &> /dev/null; then
|
||||
PORT_CHECK=$(lsof -ti:$APP_PORT 2>/dev/null)
|
||||
if [ -n "$PORT_CHECK" ]; then
|
||||
echo -e "${RED}错误: 端口 $APP_PORT 已被占用 (PID: $PORT_CHECK)${NC}"
|
||||
echo "请先停止占用端口的进程或使用 restart 命令"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查 .env 文件是否存在
|
||||
if [ ! -f ".env" ]; then
|
||||
echo -e "${YELLOW}警告: .env 文件不存在,将使用默认配置${NC}"
|
||||
echo "建议从 env.example 复制并配置 .env 文件"
|
||||
fi
|
||||
|
||||
# 检查 node_modules 是否存在
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo -e "${RED}错误: node_modules 目录不存在${NC}"
|
||||
echo "请先运行: npm install"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 启动 Node.js 应用
|
||||
echo "启动命令: NODE_ENV=$NODE_ENV nohup node $ENTRY_FILE > $LOG_FILE 2>&1 &"
|
||||
NODE_ENV=$NODE_ENV nohup node $ENTRY_FILE > $LOG_FILE 2>&1 &
|
||||
|
||||
# 获取新进程的 PID
|
||||
PID=$!
|
||||
echo $PID > "$PID_FILE"
|
||||
|
||||
# 等待应用启动
|
||||
echo "等待服务启动..."
|
||||
sleep 3
|
||||
|
||||
# 验证启动是否成功
|
||||
if ps -p $PID > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN}服务启动成功!${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo "应用名称: $APP_NAME"
|
||||
echo "进程 ID: $PID"
|
||||
echo "监听端口: $APP_PORT"
|
||||
echo "日志文件: $LOG_FILE"
|
||||
echo "PID 文件: $PID_FILE"
|
||||
echo "环境变量: NODE_ENV=$NODE_ENV"
|
||||
echo -e "${GREEN}API 文档: http://localhost:$APP_PORT/api-docs${NC}"
|
||||
echo ""
|
||||
|
||||
# 等待端口监听
|
||||
echo "检查端口监听状态..."
|
||||
sleep 2
|
||||
if command -v lsof &> /dev/null; then
|
||||
if lsof -ti:$APP_PORT > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓ 端口 $APP_PORT 正在监听${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 端口 $APP_PORT 尚未监听,请检查日志${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 显示最近的日志
|
||||
echo ""
|
||||
echo "最近的启动日志:"
|
||||
echo "------------------------"
|
||||
tail -20 "$LOG_FILE"
|
||||
else
|
||||
echo -e "${RED}========================================${NC}"
|
||||
echo -e "${RED}服务启动失败!${NC}"
|
||||
echo -e "${RED}========================================${NC}"
|
||||
echo "请检查日志文件: $LOG_FILE"
|
||||
echo ""
|
||||
echo "最近的错误日志:"
|
||||
echo "------------------------"
|
||||
tail -30 "$LOG_FILE"
|
||||
rm -f "$PID_FILE"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 重启服务函数
|
||||
function restartApp() {
|
||||
echo -e "${YELLOW}正在重启服务: $APP_NAME${NC}"
|
||||
stopApp
|
||||
sleep 3
|
||||
startApp
|
||||
}
|
||||
|
||||
# 状态检查函数
|
||||
function statusApp() {
|
||||
echo -e "${YELLOW}检查服务状态: $APP_NAME${NC}"
|
||||
echo "========================================"
|
||||
|
||||
# 如果使用 PM2 托管,优先展示 PM2 状态
|
||||
if command -v pm2 &> /dev/null; then
|
||||
if pm2 describe "$APP_NAME" > /dev/null 2>&1; then
|
||||
PM2_STATE=$(pm2 info "$APP_NAME" | grep -i "status" | awk -F":" '{print $2}' | xargs)
|
||||
echo -e "PM2 状态: ${GREEN}${PM2_STATE}${NC}"
|
||||
pm2 status "$APP_NAME"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p $PID > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓ 服务正在运行${NC}"
|
||||
echo "----------------------------------------"
|
||||
echo "进程 ID: $PID"
|
||||
echo "应用名称: $APP_NAME"
|
||||
echo "监听端口: $APP_PORT"
|
||||
|
||||
# 启动时间
|
||||
if command -v ps &> /dev/null; then
|
||||
START_TIME=$(ps -o lstart= -p $PID 2>/dev/null)
|
||||
if [ -n "$START_TIME" ]; then
|
||||
echo "启动时间: $START_TIME"
|
||||
fi
|
||||
|
||||
# 内存使用
|
||||
MEM_USAGE=$(ps -o rss= -p $PID 2>/dev/null | awk '{printf "%.2f MB", $1/1024}')
|
||||
if [ -n "$MEM_USAGE" ]; then
|
||||
echo "内存使用: $MEM_USAGE"
|
||||
fi
|
||||
|
||||
# CPU使用率
|
||||
CPU_USAGE=$(ps -o %cpu= -p $PID 2>/dev/null)
|
||||
if [ -n "$CPU_USAGE" ]; then
|
||||
echo "CPU 使用: ${CPU_USAGE}%"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查端口监听状态
|
||||
if command -v lsof &> /dev/null; then
|
||||
PORT_INFO=$(lsof -ti:$APP_PORT 2>/dev/null)
|
||||
if [ -n "$PORT_INFO" ]; then
|
||||
echo -e "端口状态: ${GREEN}监听中 ($APP_PORT)${NC}"
|
||||
else
|
||||
echo -e "端口状态: ${RED}未监听${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 日志文件信息
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
LOG_SIZE=$(du -h "$LOG_FILE" | cut -f1)
|
||||
echo "日志大小: $LOG_SIZE"
|
||||
echo "日志文件: $LOG_FILE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "最近的日志 (最后10行):"
|
||||
echo "----------------------------------------"
|
||||
tail -10 "$LOG_FILE" 2>/dev/null || echo "无法读取日志文件"
|
||||
|
||||
else
|
||||
echo -e "${RED}✗ 服务未运行 (PID 文件存在但进程不存在)${NC}"
|
||||
echo "建议清理 PID 文件: rm -f $PID_FILE"
|
||||
fi
|
||||
else
|
||||
# 通过端口检查
|
||||
if command -v lsof &> /dev/null; then
|
||||
PID=$(lsof -ti:$APP_PORT 2>/dev/null)
|
||||
if [ -n "$PID" ]; then
|
||||
echo -e "${YELLOW}⚠ 服务正在运行但未通过脚本管理${NC}"
|
||||
echo "进程 ID: $PID"
|
||||
echo "监听端口: $APP_PORT"
|
||||
echo "建议使用: ./node_manager.sh stop 停止服务后重新启动"
|
||||
else
|
||||
echo -e "${RED}✗ 服务未运行${NC}"
|
||||
echo "使用以下命令启动: ./node_manager.sh start"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗ 服务未运行 (PID 文件不存在)${NC}"
|
||||
echo "使用以下命令启动: ./node_manager.sh start"
|
||||
fi
|
||||
fi
|
||||
echo "========================================"
|
||||
}
|
||||
|
||||
# 查看日志函数
|
||||
function viewLogs() {
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
echo -e "${YELLOW}实时查看日志 (Ctrl+C 退出):${NC}"
|
||||
tail -f "$LOG_FILE"
|
||||
else
|
||||
echo -e "${RED}日志文件不存在: $LOG_FILE${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
case "$1" in
|
||||
start)
|
||||
startApp
|
||||
;;
|
||||
stop)
|
||||
stopApp
|
||||
;;
|
||||
restart)
|
||||
restartApp
|
||||
;;
|
||||
status)
|
||||
statusApp
|
||||
;;
|
||||
logs)
|
||||
viewLogs
|
||||
;;
|
||||
*)
|
||||
echo "========================================"
|
||||
echo "银行端后端(bank-backend) - 服务管理脚本"
|
||||
echo "========================================"
|
||||
echo "使用方法: $0 {start|stop|restart|status|logs}"
|
||||
echo ""
|
||||
echo "命令说明:"
|
||||
echo " start - 启动服务"
|
||||
echo " stop - 停止服务"
|
||||
echo " restart - 重启服务"
|
||||
echo " status - 查看服务状态"
|
||||
echo " logs - 实时查看日志"
|
||||
echo ""
|
||||
echo "增强说明:"
|
||||
echo " 已优先使用 PM2 管理服务(如安装了 pm2),自动重启更可靠"
|
||||
echo " 配置 PM2 开机自启: pm2 startup systemd -u $(whoami) --hp $HOME; pm2 save"
|
||||
echo ""
|
||||
echo "配置信息:"
|
||||
echo " 应用名称: $APP_NAME"
|
||||
echo " 入口文件: $ENTRY_FILE"
|
||||
echo " 监听端口: $APP_PORT"
|
||||
echo " 日志文件: $LOG_FILE"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 start # 启动服务"
|
||||
echo " $0 status # 查看状态"
|
||||
echo " $0 logs # 查看日志"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user