multi-lane-manager
Version:
Nacos 泳道管理与请求路由组件
212 lines (181 loc) • 7.73 kB
text/typescript
import type { H3Event } from 'h3';
// 使用 any 类型来避免 TypeScript 类型错误
// 因为 NitroApp 的类型定义可能与实际使用的不一致
import type { NitroApp as OriginalNitroApp } from 'nitropack';
type NitroApp = OriginalNitroApp & {
options?: {
runtimeConfig?: {
appName?: string;
public?: {
appName?: string;
};
};
};
};
import { getConfig, getGlobalState, updateConfigPort } from '../utils/config';
import { logger } from '../utils/logger';
import { registerServiceInstance, deregisterServiceInstance } from '../utils/nacos';
import { getServerPort } from './server-utils';
/**
* Nitro 插件 - 泳道管理服务注册
*
* 此插件在 Nitro 服务器启动时执行,负责:
* 1. 获取服务器端口
* 2. 注册服务实例到 Nacos
* 3. 设置服务器关闭时的注销逻辑
* 4. 提供健康检查接口
*/
// 在模块加载时立即执行的代码
logger.info(`====== 🚀 泳道管理 Nitro 插件模块被加载 ======`);
logger.debug(`⏱️ 当前时间: ${new Date().toISOString()}`);
logger.debug(`🆔 当前进程ID: ${process.pid}`);
logger.debug(`📂 当前工作目录: ${process.cwd()}`);
logger.debug(`🔧 环境变量: NODE_ENV=${process.env.NODE_ENV}, NITRO_PORT=${process.env.NITRO_PORT || '未设置'}, PORT=${process.env.PORT || '未设置'}`);
// 初始化全局状态
const globalState = getGlobalState();
if (!globalState._laneMgrRegistered) {
globalState._laneMgrRegistered = false;
globalState._laneMgrPort = undefined;
logger.debug(`🔄 初始化全局注册状态为 false`);
} else {
logger.debug(`ℹ️ 全局注册状态已存在: ${globalState._laneMgrRegistered}`);
}
/**
* Nitro 插件主函数
* 在 Nitro 服务器启动时执行,负责服务注册和健康检查
*
* @param nitroApp Nitro 应用实例
*/
export default async (nitroApp: NitroApp) => {
logger.info(`====== 🔌 泳道管理 Nitro 插件函数被调用 ======`);
logger.debug(`⏱️ 当前时间: ${new Date().toISOString()}`);
logger.debug(`✅ nitroApp 对象可用: ${!!nitroApp}`);
logger.debug(`✅ nitroApp.hooks 可用: ${!!nitroApp.hooks}`);
// 导入中间件
try {
const { default: middleware } = await import('./server-middleware');
logger.info(`✅ 成功导入中间件`);
// 添加中间件到 Nitro 应用
nitroApp.hooks.hook('request', middleware);
logger.info(`✅ 成功添加中间件到 Nitro 应用`);
} catch (error) {
logger.error(`❌ 导入或添加中间件失败: ${error instanceof Error ? error.message : String(error)}`);
}
// 尝试从Nitro运行时配置获取应用名称
try {
if (nitroApp.options && nitroApp.options.runtimeConfig) {
const appName = nitroApp.options.runtimeConfig.appName ||
(nitroApp.options.runtimeConfig.public && nitroApp.options.runtimeConfig.public.appName);
if (appName) {
// 将应用名称存储在全局变量中,以便在其他地方使用
(global as any).__nitroAppName = appName;
logger.info(`✅ 从Nitro运行时配置获取应用名称: ${appName}`);
// 清除配置缓存,强制下次获取配置时重新创建
// 这样可以确保使用最新的应用名称
const { clearConfigCache } = await import('../utils/config');
clearConfigCache();
}
}
} catch (error) {
logger.warn(`⚠️ 无法从Nitro运行时配置获取应用名称: ${error}`);
}
// 立即注册服务
(async () => {
logger.info(`====== 📝 开始注册服务 ======`);
try {
// 如果已经注册过,则跳过
if (globalState._laneMgrRegistered) {
logger.info(`ℹ️ 服务已注册,跳过重复注册`);
return;
}
// 获取服务器端口
const port = getServerPort();
// 更新配置中的端口
updateConfigPort(port);
// 标记为已注册,避免重复注册
globalState._laneMgrRegistered = true;
globalState._laneMgrPort = port;
// 注册服务实例
logger.info(`📤 开始注册服务到 Nacos,端口: ${port}`);
const success = await registerServiceInstance(port);
logger.info(`📋 服务注册结果: ${success ? '✅ 成功' : '❌ 失败'}`);
if (success) {
// 设置服务器关闭时的注销逻辑
const gracefulShutdown = async () => {
logger.info(`🛑 服务器关闭,正在注销服务...`);
await deregisterServiceInstance(port);
logger.info(`✅ 服务注销完成`);
};
// 监听进程退出事件
process.on('beforeExit', gracefulShutdown);
process.on('SIGINT', async () => {
logger.info(`🔴 收到 SIGINT 信号`);
await gracefulShutdown();
process.exit(0);
});
process.on('SIGTERM', async () => {
logger.info(`🔴 收到 SIGTERM 信号`);
await gracefulShutdown();
process.exit(0);
});
// 监听 Nitro 关闭事件
nitroApp.hooks.hook('close', async () => {
logger.info(`🔴 收到 Nitro close 事件`);
await gracefulShutdown();
});
logger.info(`✅ 已设置服务注销钩子`);
}
} catch (error) {
logger.error(`❌ 服务注册过程中出错:`, error);
}
})();
// 添加请求处理钩子,确保能拦截所有请求,包括静态资源
nitroApp.hooks.hook('request', async (event: H3Event) => {
// 检查请求是否已经被处理过,避免重复处理
if (event.context._laneManagerHandled || event.context._laneManagerProcessing) {
return;
}
// 记录所有请求,确保插件被触发
console.log(`[multi-lane-manager:nitro-plugin] Intercepting request: ${event.path}`);
// 特别记录 /_nuxt/ 路径的请求
if (event.path.startsWith('/_nuxt/')) {
console.log(`[multi-lane-manager:nitro-plugin] Intercepting _nuxt request1: ${event.path}`);
logger.info(`🔍 Nitro插件拦截到静态资源请求: ${event.path}`);
}
// 特别记录 /api/ 路径的请求
if (event.path.startsWith('/api/')) {
console.log(`[multi-lane-manager:nitro-plugin] Intercepting API request: ${event.path}`);
logger.info(`🔍 Nitro插件拦截到API请求: ${event.path}, 方法: ${event.node.req.method}`);
}
// 如果请求路径是 /api/lane-manager/health,则返回健康状态
if (event.path === '/api/lane-manager/health') {
// 标记请求正在被处理,避免重复处理
event.context._laneManagerProcessing = true;
logger.debug(`🩺 收到健康检查请求: ${event.path}`);
// 获取当前配置
const config = getConfig();
try {
// 设置响应
if (!event.node.res.headersSent) {
event.node.res.statusCode = 200;
event.node.res.setHeader('Content-Type', 'application/json');
// 返回健康状态信息
event.node.res.end(JSON.stringify({
status: 'ok',
registered: globalState._laneMgrRegistered || false,
port: globalState._laneMgrPort || null,
laneId: config.currentLaneId,
serviceName: config.serviceName,
timestamp: new Date().toISOString(),
nitroPluginLoaded: true
}));
}
} catch (error) {
logger.error(`❌ 处理健康检查请求时出错: ${error instanceof Error ? error.message : String(error)}`);
}
// 标记请求已处理
event.context._laneManagerHandled = true;
}
});
logger.info(`====== ✅ 泳道管理 Nitro 插件初始化完成 ======`);
};