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 { logger } from "./shared/observability/logger.js"; import { env } from "./config/env.js"; import { metricsRegistry } from "./shared/observability/metrics.js"; import { closeRedisClient } from "./shared/cache/redis.client.js"; import type { Request, Response } from "express"; /** * parent-bff 启动入口(对齐 02-architecture-design.md §6.7 优雅关闭)。 * * 启动顺序: * 1. initTracer(OTel SDK,可选,未配置 endpoint 时跳过) * 2. NestFactory.create + GlobalErrorFilter * 3. /metrics 端点(Prometheus 抓取) * 4. app.listen(3010) * * SIGTERM 关闭顺序(P4.1 基础版,P5+ 补充 Kafka consumer): * 1. app.close()(拒绝新请求 + 等待 in-flight) * 2. shutdownTracer()(flush OTel span) * 3. process.exit(0)(由 NestJS enableShutdownHooks 触发) */ async function bootstrap(): Promise { initTracer(); const app = await NestFactory.create(AppModule, { logger: ["log", "error", "warn"], }); app.useGlobalFilters(new GlobalErrorFilter()); app.enableShutdownHooks(); // Prometheus 指标端点:不鉴权,供 Prometheus 抓取。 app.getHttpAdapter().get("/metrics", async (_req: Request, res: Response) => { res.set("Content-Type", metricsRegistry.contentType); res.end(await metricsRegistry.metrics()); }); // CORS:默认允许 parent-portal(localhost:4002) app.enableCors({ origin: env.CORS_ORIGINS.split(",").map((o) => o.trim()), credentials: true, }); await app.listen(env.PORT); logger.info({ port: env.PORT, devMode: env.DEV_MODE }, "Parent BFF started"); process.on("SIGTERM", async () => { logger.info("Parent BFF received SIGTERM, shutting down..."); await app.close(); await closeRedisClient(); await shutdownTracer(); }); } bootstrap().catch((err: unknown) => { logger.error({ err }, "Failed to start Parent BFF"); process.exit(1); });