import "reflect-metadata"; import { NestFactory } from "@nestjs/core"; import { AppModule } from "./app.module.js"; import { GlobalErrorFilter } from "./shared/errors/global-error.filter.js"; import { initTracer, shutdownTracer } from "./shared/observability/tracer.js"; import { env } from "./config/env.js"; import { logger } from "./shared/observability/logger.js"; import { checkEsConnection } from "./config/elasticsearch.js"; import { grpcMicroserviceOptions } from "./config/grpc.js"; import { metricsRegistry } from "./shared/observability/metrics.js"; import type { Request, Response } from "express"; /** * msg 服务启动入口。 * * 仲裁依据: * - M1:gRPC 50056 启用(connectMicroservice) * - HTTP REST 3007 + gRPC 50056 双协议入口 * - enableShutdownHooks():NestJS 自动处理 SIGTERM/SIGINT → onApplicationShutdown * * 启动流程: * 1. initTracers():OpenTelemetry 链路追踪 * 2. checkEsConnection():ES 探活(降级安全,不阻断启动) * 3. NestFactory.create(AppModule):创建 app,触发 onModuleInit * - LifecycleService.onModuleInit:connectKafka + outboxPublisher.start * - KafkaConsumerService.onModuleInit:connectKafka + consumer.run * 4. connectMicroservice(grpcMicroserviceOptions):注册 gRPC 服务 * 5. startAllMicroservices():启动 gRPC 50056 * 6. listen(PORT):启动 HTTP REST 3007 */ async function bootstrap(): Promise { initTracer(); // ES 探活:未配置或失败时进入降级模式,不阻断启动。 await checkEsConnection(); const app = await NestFactory.create(AppModule, { logger: ["log", "error", "warn"], }); app.useGlobalFilters(new GlobalErrorFilter()); app.enableShutdownHooks(); // 注册 gRPC 微服务(50056) app.connectMicroservice(grpcMicroserviceOptions); // Prometheus 指标端点:不鉴权,供 Prometheus 抓取。 app.getHttpAdapter().get("/metrics", async (_req: Request, res: Response) => { res.set("Content-Type", metricsRegistry.contentType); res.end(await metricsRegistry.metrics()); }); // 启动 gRPC 微服务 + HTTP 服务 await app.startAllMicroservices(); await app.listen(env.PORT); logger.info( { httpPort: env.PORT, grpcPort: env.GRPC_PORT }, "Msg service started (HTTP + gRPC)", ); // 兜底信号处理:enableShutdownHooks 已处理 SIGTERM/SIGINT, // 此处仅确保进程退出(防止悬挂连接阻塞退出)。 const shutdown = async (signal: string): Promise => { logger.info({ signal }, "Shutting down gracefully..."); await app.close(); await shutdownTracer(); process.exit(0); }; process.on("SIGTERM", () => void shutdown("SIGTERM")); process.on("SIGINT", () => void shutdown("SIGINT")); } void bootstrap().catch((err: unknown) => { logger.error({ err }, "Failed to start msg service"); process.exit(1); });