Files
Edu/services/config-service/src/main.ts
SpecialX 1a5fa78fa6 feat(config-service): split config-service from iam for plugin/layout config
- new NestJS service on port 3011/gRPC 50059 (ADR-026)
- owns 6 config_ tables (plugin/role-mapping/role-layout/layout-tpl/user-override/outbox)
- GraphQL Federation 2 subgraph with DataLoader + RouterAuthGuard
- gRPC ConfigService + admin REST CRUD + user REST API
- three-layer merge: registry.defaultProps + roleMapping.widget_props + userOverride.props
- Redis cache with 5min TTL
- registered in apollo-router supergraph + docker-compose + port-allocation

Implements M3 of v2.1 migration plan.
2026-07-15 02:13:03 +08:00

104 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import "reflect-metadata";
import { NestFactory } from "@nestjs/core";
import { Transport, MicroserviceOptions } from "@nestjs/microservices";
import { join } from "node:path";
import { existsSync } from "node:fs";
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 { metricsRegistry } from "./shared/observability/metrics.js";
import type { Request, Response } from "express";
/**
* 解析 proto 文件路径。
* 开发环境:从 monorepo 根目录的 packages/shared-proto/proto/ 加载
* - 当 cwd 为 monorepo 根(如 CI→ packages/shared-proto/proto/config.proto
* - 当 cwd 为 services/config-servicepnpm --filter run dev→ ../../packages/shared-proto/proto/config.proto
* 生产环境Docker从服务本地的 ./proto/ 加载Dockerfile COPY
*/
function resolveProtoPath(): string {
const monorepoRootPath = join(
process.cwd(),
"packages",
"shared-proto",
"proto",
"config.proto",
);
const monorepoParentPath = join(
process.cwd(),
"..",
"..",
"packages",
"shared-proto",
"proto",
"config.proto",
);
const localPath = join(process.cwd(), "proto", "config.proto");
if (existsSync(monorepoRootPath)) return monorepoRootPath;
if (existsSync(monorepoParentPath)) return monorepoParentPath;
if (existsSync(localPath)) return localPath;
return monorepoParentPath;
}
/**
* config-service 启动入口ADR-026
*
* 双入口:
* - HTTP serverenv.PORT3011供 gateway 透传 + portal 直连
* - gRPC serverenv.GRPC_PORT50059供 BFF 聚合调用
*
* 启动顺序:
* 1. initTracerOTel SDK
* 2. 创建 NestApplication
* 3. 注册 GlobalErrorFilter
* 4. 启动 gRPC microservicehybrid app
* 5. 启动 HTTP server
*/
async function bootstrap(): Promise<void> {
initTracer();
const app = await NestFactory.create(AppModule, {
logger: ["log", "error", "warn"],
});
app.useGlobalFilters(new GlobalErrorFilter());
app.enableShutdownHooks();
// gRPC microservice端口 50059
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.GRPC,
options: {
package: "next_edu_cloud.config.v1",
protoPath: resolveProtoPath(),
url: `0.0.0.0:${env.GRPC_PORT}`,
},
});
// Prometheus 指标端点
app.getHttpAdapter().get("/metrics", async (_req: Request, res: Response) => {
res.set("Content-Type", metricsRegistry.contentType);
res.end(await metricsRegistry.metrics());
});
// 启动 hybrid appHTTP + gRPC
await app.startAllMicroservices();
await app.listen(env.PORT);
logger.info(
{ httpPort: env.PORT, grpcPort: env.GRPC_PORT },
"config-service started (HTTP + gRPC dual entry)",
);
process.on("SIGTERM", async () => {
await app.close();
await shutdownTracer();
});
}
bootstrap().catch((err: unknown) => {
logger.error({ err }, "Failed to start config-service");
process.exit(1);
});