- 5 NestJS services add /metrics endpoint via app.getHttpAdapter() - prometheus.yml scales to 8 services with rule_files and alertmanager - monitoring compose replaces blackbox with Loki+Promtail - Grafana datasource adds Loki - docker-compose.deploy.yml scales to 11 services - deploy.env.example completes Neo4j/ES/ClickHouse/LLM vars - teacher-bff adds health.controller - CI removes continue-on-error on lint step - teacher-portal lint script changed to eslint src
60 lines
2.1 KiB
TypeScript
60 lines
2.1 KiB
TypeScript
import { NestFactory } from "@nestjs/core";
|
||
import { AppModule } from "./app.module.js";
|
||
import { env } from "./config/env.js";
|
||
import { connectKafka, disconnectKafka } from "./config/kafka.js";
|
||
import { outboxPublisher } from "./shared/outbox/outbox.publisher.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 { registry } from "./shared/observability/metrics.js";
|
||
|
||
async function bootstrap(): Promise<void> {
|
||
initTracer();
|
||
|
||
const app = await NestFactory.create(AppModule, { bufferLogs: true });
|
||
app.useGlobalFilters(new GlobalErrorFilter());
|
||
app.enableShutdownHooks();
|
||
|
||
// Prometheus 指标端点:不鉴权,供 Prometheus 抓取。
|
||
// 返回 register.metrics()(Promise<string>,含 Content-Type text/plain; version=0.0.4; charset=utf-8)。
|
||
app.getHttpAdapter().get("/metrics", async (req, res) => {
|
||
res.set("Content-Type", registry.contentType);
|
||
res.end(await registry.metrics());
|
||
});
|
||
|
||
// Connect Kafka producer/consumer before starting the outbox publisher.
|
||
// Non-blocking: if Kafka is unavailable, service still starts; outbox
|
||
// publisher will retry sends and messages stay pending until Kafka recovers.
|
||
void connectKafka();
|
||
|
||
// Start the transactional outbox publisher - polls pending messages
|
||
// and publishes them to Kafka topics defined in TOPIC_MAP.
|
||
await outboxPublisher.start();
|
||
|
||
await app.listen(env.PORT);
|
||
logger.info(
|
||
{ port: env.PORT, service: "core-edu" },
|
||
"CoreEdu service is listening",
|
||
);
|
||
|
||
process.on("SIGTERM", async () => {
|
||
logger.info("SIGTERM received, shutting down gracefully...");
|
||
await outboxPublisher.stop();
|
||
await disconnectKafka();
|
||
await shutdownTracer();
|
||
await app.close();
|
||
process.exit(0);
|
||
});
|
||
|
||
process.on("SIGINT", async () => {
|
||
logger.info("SIGINT received, shutting down gracefully...");
|
||
await outboxPublisher.stop();
|
||
await disconnectKafka();
|
||
await shutdownTracer();
|
||
await app.close();
|
||
process.exit(0);
|
||
});
|
||
}
|
||
|
||
void bootstrap();
|