371 lines
10 KiB
Bash
371 lines
10 KiB
Bash
#!/bin/bash
|
||
|
||
# 即梦 Free API Node.js 启动脚本
|
||
# 使用方法: ./start-node.sh [dev|prod|stop|restart|status]
|
||
|
||
set -e
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 日志函数
|
||
log_info() {
|
||
echo -e "${BLUE}[INFO]${NC} $1"
|
||
}
|
||
|
||
log_success() {
|
||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||
}
|
||
|
||
log_warning() {
|
||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||
}
|
||
|
||
log_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
# 检查Node.js环境
|
||
check_node_env() {
|
||
if ! command -v node &> /dev/null; then
|
||
log_error "Node.js 未安装,请先安装 Node.js v20.x"
|
||
exit 1
|
||
fi
|
||
|
||
if ! command -v yarn &> /dev/null; then
|
||
log_error "Yarn 未安装,请先安装 Yarn"
|
||
exit 1
|
||
fi
|
||
|
||
NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
||
if [ "$NODE_VERSION" -lt 18 ]; then
|
||
log_warning "建议使用 Node.js v20.x,当前版本: $(node -v)"
|
||
fi
|
||
|
||
log_success "Node.js 环境检查通过: $(node -v)"
|
||
}
|
||
|
||
# 检查PM2
|
||
check_pm2() {
|
||
if ! command -v pm2 &> /dev/null; then
|
||
log_info "PM2 未安装,正在安装..."
|
||
npm install -g pm2
|
||
log_success "PM2 安装完成"
|
||
else
|
||
log_success "PM2 已安装: $(pm2 -v)"
|
||
fi
|
||
}
|
||
|
||
# 构建项目
|
||
build_project() {
|
||
log_info "构建项目..."
|
||
yarn install
|
||
yarn run build
|
||
log_success "项目构建完成"
|
||
}
|
||
|
||
# 加载环境变量文件
|
||
load_env_file() {
|
||
if [ -f ".env" ]; then
|
||
log_info "加载 .env 文件..."
|
||
export $(grep -v '^#' .env | xargs)
|
||
log_success "环境变量已从 .env 文件加载"
|
||
elif [ -f ".env.template" ]; then
|
||
log_warning "发现 .env.template 文件,请复制为 .env 并配置实际值"
|
||
log_info "命令: cp .env.template .env"
|
||
fi
|
||
}
|
||
|
||
# 验证必要的环境变量
|
||
validate_env() {
|
||
local missing_vars=()
|
||
|
||
# 检查必须的环境变量
|
||
[ -z "$MONGODB_URL" ] && missing_vars+=("MONGODB_URL")
|
||
[ -z "$TOS_ACCESS_KEY_ID" ] && missing_vars+=("TOS_ACCESS_KEY_ID")
|
||
[ -z "$TOS_ACCESS_KEY_SECRET" ] && missing_vars+=("TOS_ACCESS_KEY_SECRET")
|
||
[ -z "$TOS_BUCKET_NAME" ] && missing_vars+=("TOS_BUCKET_NAME")
|
||
|
||
if [ ${#missing_vars[@]} -gt 0 ]; then
|
||
log_error "缺少必要的环境变量:"
|
||
for var in "${missing_vars[@]}"; do
|
||
log_error " - $var"
|
||
done
|
||
log_info "请设置这些环境变量或创建 .env 文件"
|
||
log_info "参考: .env.template"
|
||
return 1
|
||
fi
|
||
|
||
log_success "环境变量验证通过"
|
||
return 0
|
||
}
|
||
|
||
# 设置环境变量 (示例)
|
||
setup_env() {
|
||
local env_type=$1
|
||
|
||
log_info "设置环境变量..."
|
||
|
||
# 先尝试加载 .env 文件
|
||
load_env_file
|
||
|
||
# 基础环境变量 (如果未设置则使用默认值)
|
||
export NODE_ENV=${NODE_ENV:-${env_type}}
|
||
export SERVICE_ID=${SERVICE_ID:-"jimeng-api-${env_type}"}
|
||
export SERVICE_NAME=${SERVICE_NAME:-"jimeng-free-api-${env_type}"}
|
||
export HOST=${HOST:-"0.0.0.0"}
|
||
export PORT=${PORT:-"3302"}
|
||
export TOS_REGION=${TOS_REGION:-"cn-beijing"}
|
||
export TOS_ENDPOINT=${TOS_ENDPOINT:-"tos-cn-beijing.volces.com"}
|
||
export HEARTBEAT_ENABLED=${HEARTBEAT_ENABLED:-"true"}
|
||
export HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-"30"}
|
||
|
||
# 验证必要的环境变量
|
||
if ! validate_env; then
|
||
exit 1
|
||
fi
|
||
|
||
log_success "环境变量设置完成"
|
||
log_info "服务ID: $SERVICE_ID"
|
||
log_info "MongoDB: ${MONGODB_URL%%\?*}" # 只显示主机部分,隐藏查询参数
|
||
log_info "TOS Region: $TOS_REGION"
|
||
}
|
||
|
||
# 直接启动 (开发模式)
|
||
start_dev() {
|
||
log_info "启动开发模式..."
|
||
setup_env "development"
|
||
|
||
if [ ! -d "dist" ]; then
|
||
build_project
|
||
fi
|
||
|
||
node dist/index.js
|
||
}
|
||
|
||
# PM2启动 (生产模式)
|
||
start_pm2() {
|
||
local env_type=$1
|
||
|
||
log_info "使用PM2启动 (${env_type}模式)..."
|
||
check_pm2
|
||
|
||
if [ ! -d "dist" ]; then
|
||
build_project
|
||
fi
|
||
|
||
# 停止现有进程
|
||
pm2 delete jimeng-free-api 2>/dev/null || true
|
||
|
||
# 启动新进程
|
||
if [ "$env_type" = "production" ]; then
|
||
pm2 start ecosystem.config.json --env production
|
||
else
|
||
pm2 start ecosystem.config.json
|
||
fi
|
||
|
||
pm2 save
|
||
log_success "PM2启动完成"
|
||
}
|
||
|
||
# 停止服务
|
||
stop_service() {
|
||
log_info "停止服务..."
|
||
|
||
# 停止PM2进程
|
||
if command -v pm2 &> /dev/null; then
|
||
pm2 delete jimeng-free-api 2>/dev/null || true
|
||
log_success "PM2进程已停止"
|
||
fi
|
||
|
||
# 停止Node.js进程
|
||
pkill -f "node dist/index.js" 2>/dev/null || true
|
||
log_success "Node.js进程已停止"
|
||
}
|
||
|
||
# 重启服务
|
||
restart_service() {
|
||
log_info "重启服务..."
|
||
stop_service
|
||
sleep 2
|
||
start_pm2 "production"
|
||
}
|
||
|
||
# 查看状态
|
||
check_status() {
|
||
log_info "检查服务状态..."
|
||
|
||
echo "=== PM2 进程状态 ==="
|
||
if command -v pm2 &> /dev/null; then
|
||
pm2 list
|
||
else
|
||
echo "PM2 未安装"
|
||
fi
|
||
|
||
echo
|
||
echo "=== Node.js 进程状态 ==="
|
||
ps aux | grep "node dist/index.js" | grep -v grep || echo "未找到 Node.js 进程"
|
||
|
||
echo
|
||
echo "=== 端口状态 ==="
|
||
netstat -tlnp 2>/dev/null | grep :3302 || echo "端口 3302 未被占用"
|
||
|
||
echo
|
||
echo "=== 服务健康检查 ==="
|
||
if curl -s http://localhost:3302/ping > /dev/null 2>&1; then
|
||
log_success "API 服务正常运行"
|
||
|
||
# 检查服务器信息
|
||
echo "=== 当前服务器信息 ==="
|
||
curl -s http://localhost:3302/api/servers/current | jq '.data' 2>/dev/null || curl -s http://localhost:3302/api/servers/current
|
||
else
|
||
log_error "API 服务无法访问"
|
||
fi
|
||
}
|
||
|
||
# 查看日志
|
||
view_logs() {
|
||
log_info "查看日志..."
|
||
|
||
if command -v pm2 &> /dev/null && pm2 list | grep -q jimeng-free-api; then
|
||
pm2 logs jimeng-free-api --lines 50
|
||
else
|
||
log_warning "PM2未运行,查看本地日志文件..."
|
||
if [ -f "./logs/combined.log" ]; then
|
||
tail -n 50 ./logs/combined.log
|
||
else
|
||
log_warning "未找到日志文件"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# 显示帮助
|
||
show_help() {
|
||
echo "即梦 Free API Node.js 启动脚本"
|
||
echo
|
||
echo "使用方法:"
|
||
echo " $0 <command>"
|
||
echo
|
||
echo "命令:"
|
||
echo " dev 直接启动开发模式 (Node.js)"
|
||
echo " prod 使用PM2启动生产模式"
|
||
echo " pm2 使用PM2启动开发模式"
|
||
echo " stop 停止所有服务"
|
||
echo " restart 重启PM2服务"
|
||
echo " status 查看服务状态"
|
||
echo " logs 查看服务日志"
|
||
echo " build 仅构建项目"
|
||
echo " help 显示此帮助信息"
|
||
echo
|
||
echo "多实例管理:"
|
||
echo " ./multi-instance.sh start all production # 启动所有实例 (端口 3302, 3303, 3304)"
|
||
echo " ./multi-instance.sh start 3302,3303 # 启动指定端口实例"
|
||
echo " ./multi-instance.sh stop all # 停止所有实例"
|
||
echo " ./multi-instance.sh status # 查看所有实例状态"
|
||
echo " ./multi-instance.sh logs 3302 # 查看指定实例日志"
|
||
echo
|
||
echo "环境变量配置方式:"
|
||
echo " 方式1: 使用 .env 文件 (推荐)"
|
||
echo " cp .env.template .env"
|
||
echo " # 编辑 .env 文件,填入实际配置"
|
||
echo " $0 prod"
|
||
echo
|
||
echo " 方式2: 直接设置环境变量"
|
||
echo " export MONGODB_URL='mongodb://localhost:27017/jimeng-api'"
|
||
echo " export TOS_ACCESS_KEY_ID='your_key_id'"
|
||
echo " # ... 其他变量"
|
||
echo " $0 prod"
|
||
echo
|
||
echo " 方式3: PM2 ecosystem 配置"
|
||
echo " # 编辑 ecosystem.config.json 中的 env 或 env_production 节点"
|
||
echo " pm2 start ecosystem.config.json --env production"
|
||
echo
|
||
echo "必须设置的环境变量:"
|
||
echo " MONGODB_URL MongoDB连接地址"
|
||
echo " TOS_ACCESS_KEY_ID TOS访问密钥ID"
|
||
echo " TOS_ACCESS_KEY_SECRET TOS访问密钥"
|
||
echo " TOS_BUCKET_NAME TOS存储桶名称"
|
||
echo
|
||
echo "可选环境变量 (有默认值):"
|
||
echo " NODE_ENV 运行环境 (development/production)"
|
||
echo " SERVICE_ID 服务器唯一标识"
|
||
echo " SERVICE_NAME 服务器名称"
|
||
echo " HOST 绑定主机 (默认: 0.0.0.0)"
|
||
echo " PORT 端口号 (默认: 3302)"
|
||
echo " BASE_URL 服务器基础URL (自动检测)"
|
||
echo " TOS_REGION TOS地区 (默认: cn-beijing)"
|
||
echo " TOS_ENDPOINT TOS端点 (默认: tos-cn-beijing.volces.com)"
|
||
echo " TOS_SELF_DOMAIN TOS自定义域名"
|
||
echo " HEARTBEAT_ENABLED 启用心跳 (默认: true)"
|
||
echo " HEARTBEAT_INTERVAL 心跳间隔秒数 (默认: 30)"
|
||
echo
|
||
echo "示例:"
|
||
echo " # 快速开始 (使用 .env 文件)"
|
||
echo " cp .env.template .env"
|
||
echo " # 编辑 .env 文件后:"
|
||
echo " $0 prod"
|
||
echo
|
||
echo " # 临时环境变量启动"
|
||
echo " MONGODB_URL='mongodb://localhost:27017/jimeng-api' \\"
|
||
echo " TOS_ACCESS_KEY_ID='your_key' \\"
|
||
echo " TOS_ACCESS_KEY_SECRET='your_secret' \\"
|
||
echo " TOS_BUCKET_NAME='your_bucket' \\"
|
||
echo " $0 dev"
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
local command="$1"
|
||
|
||
case "$command" in
|
||
dev)
|
||
check_node_env
|
||
start_dev
|
||
;;
|
||
prod)
|
||
check_node_env
|
||
start_pm2 "production"
|
||
;;
|
||
pm2)
|
||
check_node_env
|
||
start_pm2 "development"
|
||
;;
|
||
stop)
|
||
stop_service
|
||
;;
|
||
restart)
|
||
check_node_env
|
||
restart_service
|
||
;;
|
||
status)
|
||
check_status
|
||
;;
|
||
logs)
|
||
view_logs
|
||
;;
|
||
build)
|
||
check_node_env
|
||
build_project
|
||
;;
|
||
help|--help|-h)
|
||
show_help
|
||
;;
|
||
"")
|
||
log_error "请指定命令"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
*)
|
||
log_error "未知命令: $command"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 执行主函数
|
||
main "$@" |