perf(web): cache dashboard tile responses

This commit is contained in:
vince 2026-06-20 14:03:24 +02:00
parent cda40401ca
commit bc1f64d566
2 changed files with 386 additions and 4 deletions

View file

@ -1,6 +1,12 @@
import { describe, expect, test, vi } from "vitest";
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
import { loadDashboardResponse, loadDashboardTileResponse } from "./dashboard";
import {
createDashboardTileCache,
dashboardTileCacheKey,
handleDashboardTileRoute,
loadDashboardResponse,
loadDashboardTileResponse,
} from "./dashboard";
describe("dashboard API route", () => {
test("returns the ready dashboard shell without hydrating live datasources", async () => {
@ -145,6 +151,243 @@ describe("dashboard API route", () => {
});
});
test("caches ready tile responses until the tile ttl expires", async () => {
const cache = createDashboardTileCache();
let now = 1_000;
const fetch = vi.fn(async () =>
jsonResponse({
status: "UP",
ping: 42,
}),
);
const tile = { kind: "service", groupId: "essentials", id: "vaultwarden" } as const;
const first = await loadDashboardTileResponse(tile, {
fetch,
now: () => now,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
const second = await loadDashboardTileResponse(tile, {
fetch,
now: () => now + 29_999,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
now += 30_001;
const third = await loadDashboardTileResponse(tile, {
fetch,
now: () => now,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
expect(first).toEqual(second);
expect(third.state).toBe("ready");
expect(fetch).toHaveBeenCalledTimes(2);
});
test("keeps telemetry tiles cached for fifteen seconds", async () => {
const cache = createDashboardTileCache();
let now = 1_000;
const fetch = telemetryFetch();
const tile = { kind: "telemetry", id: "infra-ram" } as const;
await loadDashboardTileResponse(tile, {
fetch,
now: () => now,
prometheusBaseUrl: "https://prometheus.example",
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
await loadDashboardTileResponse(tile, {
fetch,
now: () => now + 14_999,
prometheusBaseUrl: "https://prometheus.example",
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
now += 15_001;
await loadDashboardTileResponse(tile, {
fetch,
now: () => now,
prometheusBaseUrl: "https://prometheus.example",
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
expect(fetch).toHaveBeenCalledTimes(4);
});
test("keeps weather module tiles cached for ten minutes", async () => {
const cache = createDashboardTileCache();
let now = 1_000;
const fetch = vi.fn(async () =>
jsonResponse({
current: {
apparent_temperature: 19,
temperature_2m: 20,
weather_code: 0,
wind_speed_10m: 11,
},
}),
);
const tile = { kind: "module", id: "weather-amsterdam" } as const;
await loadDashboardTileResponse(tile, {
fetch,
now: () => now,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
await loadDashboardTileResponse(tile, {
fetch,
now: () => now + 599_999,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
now += 600_001;
await loadDashboardTileResponse(tile, {
fetch,
now: () => now,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
expect(fetch).toHaveBeenCalledTimes(2);
});
test("coalesces concurrent tile requests for the same cache key", async () => {
const cache = createDashboardTileCache();
let resolveFetch: ((response: Response) => void) | undefined;
const fetch = vi.fn(() =>
new Promise<Response>((resolve) => {
resolveFetch = resolve;
})
);
const tile = { kind: "service", groupId: "essentials", id: "vaultwarden" } as const;
const first = loadDashboardTileResponse(tile, {
fetch,
now: () => 1_000,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
const second = loadDashboardTileResponse(tile, {
fetch,
now: () => 1_000,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
});
await Promise.resolve();
expect(fetch).toHaveBeenCalledTimes(1);
resolveFetch?.(jsonResponse({ status: "UP", ping: 42 }));
expect(await first).toEqual(await second);
});
test("uses structured tile cache keys when identifiers contain delimiters", () => {
expect(
dashboardTileCacheKey({ kind: "service", groupId: "a:b", id: "c" }),
).not.toBe(
dashboardTileCacheKey({ kind: "service", groupId: "a", id: "b:c" }),
);
expect(
dashboardTileCacheKey({ kind: "status", stripId: "a:b", id: "c" }),
).not.toBe(
dashboardTileCacheKey({ kind: "status", stripId: "a", id: "b:c" }),
);
});
test("uses thirty-second status aggregate and five-minute static status ttl buckets", async () => {
const cache = createDashboardTileCache();
const fetch = vi.fn(async () => jsonResponse({ status: "UP", ping: 42 }));
const serviceCheckCount = dimensionLabDashboardFixture.serviceGroups
.flatMap((group) => group.services).length;
await loadDashboardTileResponse(
{ kind: "status", stripId: "footer-status", id: "system-status" },
{
fetch,
now: () => 1_000,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
},
);
await loadDashboardTileResponse(
{ kind: "status", stripId: "footer-status", id: "system-status" },
{
fetch,
now: () => 31_001,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
},
);
await loadDashboardTileResponse(
{ kind: "status", stripId: "footer-status", id: "auto-refresh" },
{
fetch,
now: () => 1_000,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
},
);
await loadDashboardTileResponse(
{ kind: "status", stripId: "footer-status", id: "auto-refresh" },
{
fetch,
now: () => 300_999,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
},
);
await loadDashboardTileResponse(
{ kind: "status", stripId: "footer-status", id: "auto-refresh" },
{
fetch,
now: () => 301_001,
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: cache,
},
);
expect(fetch).toHaveBeenCalledTimes(serviceCheckCount * 2);
});
test("serves tile route responses with short private cache headers", async () => {
const response = await handleDashboardTileRoute(
"/api/dashboard/tile/service/essentials/vaultwarden",
{
fetch: vi.fn(async () => jsonResponse({ status: "UP", ping: 42 })),
refreshSeedDocument: true,
seedIfEmpty: true,
tileCache: createDashboardTileCache(),
},
);
expect(response.headers.get("cache-control")).toBe(
"private, max-age=5, stale-while-revalidate=30",
);
});
test("does not hydrate tile routes when live datasources are disabled", async () => {
const previous = process.env.DISABLE_LIVE_DATASOURCES;
process.env.DISABLE_LIVE_DATASOURCES = "1";
@ -179,3 +422,43 @@ function jsonResponse(payload: unknown): Response {
headers: { "content-type": "application/json" },
});
}
function telemetryFetch() {
return vi.fn(async (input: RequestInfo | URL) => {
const url = String(input);
if (url.startsWith("https://prometheus.example/api/v1/query_range")) {
return jsonResponse({
status: "success",
data: {
result: [
{
metric: { host: "linux-infra" },
values: [
[1771430000, "10"],
[1771430060, "20"],
[1771430120, "42"],
],
},
],
},
});
}
if (url.startsWith("https://prometheus.example/api/v1/query")) {
return jsonResponse({
status: "success",
data: {
result: [
{
metric: { host: "linux-infra" },
value: [1771430400, "42"],
},
],
},
});
}
throw new Error(`Unhandled test request: ${url}`);
});
}