jimeng-free-api/multi-instance.sh

312 lines
8.1 KiB
Bash

#!/bin/bash
# 即梦 Free API 多实例 PM2 管理脚本
# 使用方法: ./multi-instance.sh [start|stop|restart|status|logs] [port1,port2,port3|all]
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"
}
# 可用的端口列表
AVAILABLE_PORTS=(3302 3303 3304)
ALL_APPS=("jimeng-api-3302" "jimeng-api-3303" "jimeng-api-3304")
# 检查PM2
check_pm2() {
if ! command -v pm2 &> /dev/null; then
log_error "PM2 未安装,请先安装 PM2"
log_info "npm install -g pm2"
exit 1
fi
}
# 构建项目
build_project() {
if [ ! -d "dist" ]; then
log_info "构建项目..."
yarn install
yarn run build
log_success "项目构建完成"
fi
}
# 解析端口参数
parse_ports() {
local port_arg=$1
local target_ports=()
if [ "$port_arg" = "all" ] || [ -z "$port_arg" ]; then
target_ports=("${AVAILABLE_PORTS[@]}")
else
IFS=',' read -ra PORTS <<< "$port_arg"
for port in "${PORTS[@]}"; do
if [[ " ${AVAILABLE_PORTS[@]} " =~ " ${port} " ]]; then
target_ports+=("$port")
else
log_warning "无效端口: $port (可用端口: ${AVAILABLE_PORTS[*]})"
fi
done
fi
echo "${target_ports[@]}"
}
# 获取应用名称
get_app_name() {
local port=$1
echo "jimeng-api-${port}"
}
# 启动指定端口的服务
start_services() {
local ports_str=$1
local env_mode=${2:-production}
local target_ports=($(parse_ports "$ports_str"))
if [ ${#target_ports[@]} -eq 0 ]; then
log_error "没有有效的端口"
return 1
fi
log_info "启动服务实例..."
build_project
for port in "${target_ports[@]}"; do
local app_name=$(get_app_name "$port")
log_info "启动 $app_name (端口 $port)..."
# 停止现有实例
pm2 delete "$app_name" 2>/dev/null || true
# 启动新实例
if [ "$env_mode" = "production" ]; then
pm2 start ecosystem.config.json --only "$app_name" --env production
else
pm2 start ecosystem.config.json --only "$app_name"
fi
# 等待启动完成
sleep 2
# 检查启动状态
if pm2 list | grep -q "$app_name.*online"; then
log_success "$app_name 启动成功 (http://localhost:$port)"
else
log_error "$app_name 启动失败"
fi
done
pm2 save
log_success "所有服务启动完成"
}
# 停止指定端口的服务
stop_services() {
local ports_str=$1
local target_ports=($(parse_ports "$ports_str"))
if [ ${#target_ports[@]} -eq 0 ]; then
log_error "没有有效的端口"
return 1
fi
log_info "停止服务实例..."
for port in "${target_ports[@]}"; do
local app_name=$(get_app_name "$port")
log_info "停止 $app_name..."
pm2 delete "$app_name" 2>/dev/null || log_warning "$app_name 不存在或已停止"
done
log_success "服务停止完成"
}
# 重启服务
restart_services() {
local ports_str=$1
local env_mode=${2:-production}
log_info "重启服务..."
stop_services "$ports_str"
sleep 2
start_services "$ports_str" "$env_mode"
}
# 查看服务状态
check_status() {
local ports_str=$1
local target_ports=($(parse_ports "$ports_str"))
echo "=== PM2 进程列表 ==="
pm2 list
echo
echo "=== 服务详细状态 ==="
if [ ${#target_ports[@]} -eq 0 ]; then
target_ports=("${AVAILABLE_PORTS[@]}")
fi
for port in "${target_ports[@]}"; do
local app_name=$(get_app_name "$port")
echo "--- $app_name (端口 $port) ---"
if pm2 list | grep -q "$app_name"; then
local status=$(pm2 list | grep "$app_name" | awk '{print $10}')\n log_info "状态: $status"
# 健康检查
if curl -s "http://localhost:$port/ping" > /dev/null 2>&1; then
log_success "健康检查: 正常"
# 获取服务器信息
local server_info=$(curl -s "http://localhost:$port/api/servers/current" 2>/dev/null || echo "{}")\n if [ "$server_info" != "{}" ]; then
log_info "服务器信息: $(echo "$server_info" | jq -r '.data.server_id // "unknown"' 2>/dev/null || echo "获取失败")"
fi
else
log_error "健康检查: 失败"
fi
else
log_warning "进程不存在"
fi
echo
done
echo "=== 端口占用情况 ==="
for port in "${target_ports[@]}"; do
if netstat -tlnp 2>/dev/null | grep ":$port " > /dev/null; then
log_success "端口 $port: 已占用"
else
log_warning "端口 $port: 未占用"
fi
done
}
# 查看日志
view_logs() {
local ports_str=$1
local target_ports=($(parse_ports "$ports_str"))
if [ ${#target_ports[@]} -eq 0 ]; then
log_error "没有有效的端口"
return 1
fi
if [ ${#target_ports[@]} -eq 1 ]; then
# 单个服务,显示实时日志
local app_name=$(get_app_name "${target_ports[0]}")
log_info "查看 $app_name 实时日志..."
pm2 logs "$app_name" --lines 50
else
# 多个服务,显示最近日志
for port in "${target_ports[@]}"; do
local app_name=$(get_app_name "$port")
echo "=== $app_name 最近日志 ==="
pm2 logs "$app_name" --lines 20 --nostream
echo
done
fi
}
# 显示帮助
show_help() {
echo "即梦 Free API 多实例 PM2 管理脚本"
echo
echo "使用方法:"
echo " $0 <command> [ports] [env]"
echo
echo "命令:"
echo " start 启动服务实例"
echo " stop 停止服务实例"
echo " restart 重启服务实例"
echo " status 查看服务状态"
echo " logs 查看服务日志"
echo " help 显示此帮助信息"
echo
echo "端口参数:"
echo " all 所有端口 (默认)"
echo " 3302 仅端口 3302"
echo " 3302,3303 多个端口,用逗号分隔"
echo " 可用端口: ${AVAILABLE_PORTS[*]}"
echo
echo "环境参数 (仅 start/restart):"
echo " production 生产环境 (默认)"
echo " development 开发环境"
echo
echo "示例:"
echo " $0 start all production # 启动所有实例 (生产环境)"
echo " $0 start 3302,3303 development # 启动端口 3302 和 3303 (开发环境)"
echo " $0 stop 3304 # 停止端口 3304"
echo " $0 restart all # 重启所有实例"
echo " $0 status # 查看所有实例状态"
echo " $0 logs 3302 # 查看端口 3302 的日志"
echo
echo "服务访问地址:"
for port in "${AVAILABLE_PORTS[@]}"; do
echo " - http://localhost:$port (jimeng-api-$port)"
done
}
# 主函数
main() {
local command="$1"
local ports="$2"
local env_mode="${3:-production}"
check_pm2
case "$command" in
start)
start_services "$ports" "$env_mode"
;;
stop)
stop_services "$ports"
;;
restart)
restart_services "$ports" "$env_mode"
;;
status)
check_status "$ports"
;;
logs)
view_logs "$ports"
;;
help|--help|-h)
show_help
;;
"")
log_error "请指定命令"
show_help
exit 1
;;
*)
log_error "未知命令: $command"
show_help
exit 1
;;
esac
}
# 执行主函数
main "$@"