完善 readiness、发布追溯与敏感治理(07-15-production-trust-closeout-cleanup)

这个提交包含在:
2026-07-16 05:17:38 +08:00
父节点 abb6a22f5c
当前提交 28e8e746b7
共修改 29 个文件,包含 1849 行新增和 233 行删除
+13 -13
查看文件
@@ -104,8 +104,10 @@ function setStaticCacheHeaders(res, filePath) {
}
}
async function buildApp() {
async function buildApp(dependencies = {}) {
const config = getConfig();
const prismaPluginImpl = dependencies.prismaPlugin ?? prismaPlugin;
const startJobsImpl = dependencies.startJobs ?? startJobs;
const app = fastify({
logger: {
@@ -246,7 +248,7 @@ async function buildApp() {
});
});
await app.register(prismaPlugin);
await app.register(prismaPluginImpl);
await app.register(authPlugin);
if (config.nodeEnv !== "production" && config.openapiDocsEnabled) {
@@ -254,10 +256,6 @@ async function buildApp() {
app.log.info("OpenAPI docs enabled at /api/docs");
}
if (config.otelTracesEnabled) {
app.log.info("OTel tracing enabled");
}
app.get(
"/health",
{
@@ -267,16 +265,17 @@ async function buildApp() {
response: {
200: buildDataEnvelopeSchema({
type: "object",
required: ["ok"],
required: ["ok", "buildSha"],
properties: {
ok: { type: "boolean" },
buildSha: { type: "string" },
},
}),
},
},
},
async (request, reply) => {
return reply.send({ requestId: request.id, data: { ok: true } });
return reply.send({ requestId: request.id, data: { ok: true, buildSha: app.config.buildSha } });
},
);
@@ -289,16 +288,17 @@ async function buildApp() {
response: {
200: buildDataEnvelopeSchema({
type: "object",
required: ["ok"],
required: ["ok", "buildSha"],
properties: {
ok: { type: "boolean" },
buildSha: { type: "string" },
},
}),
503: buildErrorEnvelopeSchema({
description: "数据库不可用",
codeExample: "SYS_503",
messageExample: "Service Unavailable",
detailsExample: { db: "unreachable" },
detailsExample: { db: "unreachable", buildSha: "abcdef123456" },
}),
},
},
@@ -306,14 +306,14 @@ async function buildApp() {
async (request, reply) => {
try {
await app.prisma.$queryRaw`SELECT 1`;
return reply.send({ requestId: request.id, data: { ok: true } });
return reply.send({ requestId: request.id, data: { ok: true, buildSha: app.config.buildSha } });
} catch (error) {
app.log.error({ err: error, requestId: request.id }, "Readiness check failed");
throw new AppError({
code: "SYS_503",
message: "Service Unavailable",
statusCode: 503,
details: { db: "unreachable" },
details: { db: "unreachable", buildSha: app.config.buildSha },
});
}
},
@@ -399,7 +399,7 @@ async function buildApp() {
await app.register(aiRoutes, { prefix: "/api" });
await app.register(exportsRoutes, { prefix: "/api" });
await startJobs(app);
await startJobsImpl(app);
return app;
}
+6
查看文件
@@ -11,6 +11,11 @@ function requiredEnv(name) {
return value;
}
function normalizeBuildSha(value) {
const sha = String(value || "").trim().toLowerCase();
return /^[0-9a-f]{7,64}$/.test(sha) ? sha.slice(0, 12) : "unknown";
}
function getConfig() {
const nodeEnv = process.env.NODE_ENV ?? "development";
const serverRoot = path.resolve(__dirname, "..");
@@ -21,6 +26,7 @@ function getConfig() {
nodeEnv,
port: Number(process.env.PORT ?? 3000),
host: process.env.HOST ?? "0.0.0.0",
buildSha: normalizeBuildSha(process.env.BUILD_SHA),
metricsEnabled: process.env.METRICS_ENABLED !== "false",