feat(devops): separate public page server timing diagnostics
CI / check (push) Successful in 2m23s
CI / deploy (push) Successful in 1m13s
CI / publish-container (push) Successful in 44s

This commit is contained in:
Simo committed 2026-09-11 10:49:08 +02:00
1 parent d5091d1a73
commit baeb54aeb5
15 files changed
+315 -29

No files matched your search

+28 -9
View File
@@ -11,6 +11,8 @@ const measurement = z.object({
errors: z.number().nonnegative(),
});
const schema = z.object({
kind: z.enum(["admin-api", "public-page"]).optional(),
outcome: z.enum(["completed", "failed", "redirect", "not-found"]).optional(),
operationId: z.string().max(100),
route: z.string().max(300),
method: z.string().max(10),
@@ -24,6 +26,8 @@ const schema = z.object({
}),
});
export interface PerformanceSample {
kind?: "admin-api" | "public-page";
outcome?: "completed" | "failed" | "redirect" | "not-found";
operationId: string;
route: string;
method: string;
@@ -33,23 +37,33 @@ export interface PerformanceSample {
metrics: PerformanceMetrics;
}
const state = globalThis as typeof globalThis & {
cmsPerformance?: { samples: PerformanceSample[]; pending: number };
cmsPerformance?: {
samples: PerformanceSample[];
publicSamples?: PerformanceSample[];
pending: number;
};
};
const buffer = state.cmsPerformance ?? { samples: [], pending: 0 };
state.cmsPerformance = buffer;
/** Best effort: no connection wait, no unbounded offline queue, no request failure. */
export function recordPerformance(sample: PerformanceSample): void {
buffer.samples.unshift(sample);
buffer.samples.length = Math.min(buffer.samples.length, LIMIT);
const samples =
sample.kind === "public-page"
? (buffer.publicSamples ?? [])
: buffer.samples;
if (sample.kind === "public-page") buffer.publicSamples = samples;
samples.unshift(sample);
samples.length = Math.min(samples.length, LIMIT);
const key = sample.kind === "public-page" ? `${KEY}:public` : KEY;
if (redis?.status !== "ready" || buffer.pending >= 4) return;
buffer.pending++;
try {
void redis
.multi()
.lpush(KEY, JSON.stringify(sample))
.ltrim(KEY, 0, LIMIT - 1)
.expire(KEY, 3600)
.lpush(key, JSON.stringify(sample))
.ltrim(key, 0, LIMIT - 1)
.expire(key, 3600)
.exec()
.catch(() => undefined)
.finally(() => {
@@ -60,16 +74,21 @@ export function recordPerformance(sample: PerformanceSample): void {
}
}
export async function readPerformance(): Promise<{
export async function readPerformance(
kind: "admin-api" | "public-page" = "admin-api",
): Promise<{
samples: PerformanceSample[];
shared: boolean;
}> {
const cutoff = Date.now() - RETENTION_MS;
const key = kind === "public-page" ? `${KEY}:public` : KEY;
const local =
kind === "public-page" ? (buffer.publicSamples ?? []) : buffer.samples;
if (redis?.status === "ready") {
let timer: ReturnType<typeof setTimeout> | undefined;
try {
const rows = await Promise.race([
redis.lrange(KEY, 0, LIMIT - 1),
redis.lrange(key, 0, LIMIT - 1),
new Promise<never>((_, reject) => {
timer = setTimeout(
() => reject(new Error("Diagnostic storage timeout")),
@@ -95,7 +114,7 @@ export async function readPerformance(): Promise<{
}
}
return {
samples: buffer.samples.filter((sample) => sample.at >= cutoff),
samples: local.filter((sample) => sample.at >= cutoff),
shared: false,
};
}