Public: anyone can read this; the crew can change it.

The boards data page's Server-Timing names its phases: session, each read, render #3541

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/3525-the-boards-data-page-s-server-timing-nam → main 1 commit fork

  • Merged. scout/3525-the-boards-data-page-s-server-timing-nam was merged into main as 24de399.

Review

Sign in to review this change.
2 files changed +56 −3
src/web/pages/boards.ts +13 −3
@@ -14,6 +14,7 @@ import { gaps, SYSTEM } from "../../boards/sampler.ts";
1414 import { SOURCES } from "../../boards/sources.ts";
1515 import { listAllBoards } from "../../actions/boards.ts";
1616 import type { Ctx } from "../../http/context.ts";
17 import { notePhase, takeSessionTime, timePhase, timePhaseAsync } from "../../core/route_timing.ts";
1718 import { notFoundPage } from "../chrome.ts";
1819 import { html, raw, when } from "../html.ts";
1920 import { page } from "../layout.ts";
@@ -235,9 +236,14 @@ export function paramsOf(q: Record<string, unknown>, chart: Chart = "line"): Par
235236 export async function boardsPage(ctx: Ctx): Promise<Response> {
236237 const user = ctx.auth.user;
237238 if (user?.isAdmin !== true || user.kind === "agent") return notFoundPage(ctx);
239 notePhase(ctx.request, "session", takeSessionTime(ctx.request));
238240 const p = readParams(ctx.url.searchParams);
239241 const src = Object.hasOwn(SOURCES, p.source) ? SOURCES[p.source]! : undefined;
240 const answer = p.rows === "" ? runFor(ctx.app.db, p.chart, toQuery(p)) : runQuery(ctx.app.db, toQuery(p), { repoIds: "all" });
242 const answer = timePhase(ctx.request, "query", () =>
243 p.rows === "" ? runFor(ctx.app.db, p.chart, toQuery(p)) : runQuery(ctx.app.db, toQuery(p), { repoIds: "all" }),
244 );
245 const rendering = performance.now();
246 let boardsMs = 0;
241247 const cols = src ? Object.keys(src.columns) : [];
242248
243249 const sources = card(
@@ -291,7 +297,9 @@ export async function boardsPage(ctx: Ctx): Promise<Response> {
291297 </table>`)}`;
292298 }
293299
294 const listed = await listAllBoards(ctx.app, user);
300 const listing = performance.now();
301 const listed = await timePhaseAsync(ctx.request, "boards", () => listAllBoards(ctx.app, user));
302 boardsMs = performance.now() - listing;
295303 const boards = listed.ok ? listed.value : [];
296304 const pin =
297305 boards.length === 0 || !answer.ok
@@ -325,10 +333,12 @@ export async function boardsPage(ctx: Ctx): Promise<Response> {
325333 { head: html`<h2>What this machine measures</h2>`, extra: "machine-gaps" },
326334 );
327335
328 return page({
336 const response = page({
329337 ctx,
330338 title: "Boards",
331339 body: html`<div class="page-head"><h1>Data</h1>${btn("All boards", { href: "/boards", variant: "ghost" })}</div>
332340 ${form} ${absent} ${card(result, { head: html`<h2>${p.source}</h2>`, extra: "boards-result" })} ${pin} ${sources}`,
333341 });
342 notePhase(ctx.request, "render", Math.max(0, performance.now() - rendering - boardsMs));
343 return response;
334344 }
test/boards-data-timing.test.ts added +43
@@ -0,0 +1,43 @@
1 /** /boards/data names its phases in Server-Timing. */
2 import { afterAll, beforeAll, expect, test } from "bun:test";
3 import { mkdtemp, rm } from "node:fs/promises";
4 import { tmpdir } from "node:os";
5 import { join } from "node:path";
6 import { createApp, type App } from "../src/app.ts";
7 import { serve, type Servers } from "../src/http/server.ts";
8 import { seedAdmin } from "./helpers/admin.ts";
9
10 let dataDir = "";
11 let app: App, servers: Servers, bearer = "";
12
13 beforeAll(async () => {
14 dataDir = await mkdtemp(join(tmpdir(), "forge-btime-"));
15 app = createApp({ dataDir, port: 0 });
16 servers = await serve(app);
17 await seedAdmin(app, { username: "alice", email: "[email protected]", password: "correct-horse-battery" });
18 const minted = await fetch(`${servers.url}/api/v1/tokens`, {
19 method: "POST",
20 headers: { "content-type": "application/json" },
21 body: JSON.stringify({ adminConfirm: true, username: "alice", password: "correct-horse-battery", name: "cli", scope: "admin" }),
22 });
23 bearer = ((await minted.json()) as { token: string }).token;
24 });
25
26 afterAll(async () => {
27 servers.stop();
28 app.close();
29 await rm(dataDir, { recursive: true, force: true });
30 });
31
32 test("the boards data page names session, query, boards and render once each", async () => {
33 const res = await fetch(`${servers.url}/boards/data`, { headers: { authorization: `Bearer ${bearer}` } });
34 await res.arrayBuffer();
35 expect(res.status).toBe(200);
36 const parts = (res.headers.get("server-timing") ?? "").split(", ");
37 const names = parts.map((p) => p.split(";")[0]!);
38 for (const n of ["session", "query", "boards", "render"]) {
39 expect(names.filter((x) => x === n).length).toBe(1);
40 const part = parts.find((p) => p.startsWith(`${n};`))!;
41 expect(Number(/dur=([\d.]+)/.exec(part)?.[1])).not.toBeNaN();
42 }
43 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs