Files
nxxmdata/backend/node_manager.sh
2025-11-04 09:43:23 +08:00

329 lines
10 KiB
Bash

#!/bin/bash
# Node.js 服务管理脚本 - 宁夏智慧养殖监管平台后端
# 使用方法: ./node_manager.sh [start|stop|restart|status]
# 配置区域
APP_NAME="nxxmdata-backend"
ENTRY_FILE="server.js"
APP_PORT="5350"
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}"
# 停止服务函数
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}"
# 检查服务是否已经运行
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 "========================================"
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 "宁夏智慧养殖监管平台 - 服务管理脚本"
echo "========================================"
echo "使用方法: $0 {start|stop|restart|status|logs}"
echo ""
echo "命令说明:"
echo " start - 启动服务"
echo " stop - 停止服务"
echo " restart - 重启服务"
echo " status - 查看服务状态"
echo " logs - 实时查看日志"
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