66 lines
2.4 KiB
TypeScript
66 lines
2.4 KiB
TypeScript
// teacher-bff 入口(B1 裁决:P2 起 GraphQL Yoga)
|
||
// 优雅关闭顺序(G9):HTTP → Redis → gRPC → Tracer
|
||
import "reflect-metadata";
|
||
import { NestFactory } from "@nestjs/core";
|
||
import type { NestExpressApplication } from "@nestjs/platform-express";
|
||
import type { Application, Request, Response } from "express";
|
||
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 { closeAllGrpcClients } from "./clients/grpc/grpc.factory.js";
|
||
|
||
async function bootstrap(): Promise<void> {
|
||
initTracer();
|
||
|
||
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
||
logger: ["log", "error", "warn"],
|
||
});
|
||
|
||
app.useGlobalFilters(new GlobalErrorFilter());
|
||
app.enableShutdownHooks();
|
||
|
||
// Prometheus 指标端点:不鉴权,供 Prometheus 抓取
|
||
// 直接获取 Express 实例注册路由,避免 HttpAdapter 泛型类型不兼容
|
||
const expressApp = app.getHttpAdapter().getInstance() as Application;
|
||
expressApp.get("/metrics", async (_req: Request, res: Response) => {
|
||
res.set("Content-Type", metricsRegistry.contentType);
|
||
res.end(await metricsRegistry.metrics());
|
||
});
|
||
|
||
await app.listen(env.PORT);
|
||
logger.info(
|
||
{
|
||
port: env.PORT,
|
||
graphql: env.GRAPHQL_PATH,
|
||
devMode: env.TEACHER_BFF_DEV_MODE,
|
||
iamTarget: env.IAM_GRPC_TARGET,
|
||
},
|
||
"Teacher BFF started (GraphQL + gRPC downstream)",
|
||
);
|
||
|
||
// 优雅关闭(G9:HTTP → Redis → gRPC → Tracer)
|
||
const shutdown = async (signal: string) => {
|
||
logger.info({ signal }, "Shutting down Teacher BFF");
|
||
try {
|
||
await app.close(); // 触发 OnModuleDestroy(Redis quit)
|
||
closeAllGrpcClients(); // 关闭所有 gRPC channel
|
||
await shutdownTracer();
|
||
logger.info("Teacher BFF shutdown complete");
|
||
} catch (err) {
|
||
logger.error({ err }, "Error during shutdown");
|
||
process.exit(1);
|
||
}
|
||
};
|
||
|
||
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
||
process.on("SIGINT", () => void shutdown("SIGINT"));
|
||
}
|
||
|
||
bootstrap().catch((err: unknown) => {
|
||
logger.error({ err }, "Failed to start Teacher BFF");
|
||
process.exit(1);
|
||
});
|