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

The API's search names its Server-Timing phases: session, search, render #3927

Merged opened this

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

Merged

scout/forge:scout/3919-the-api-s-search-names-its-server-timing → main 2 commits fork

  • Merged. scout/3919-the-api-s-search-names-its-server-timing was merged into main as 620d1de.

Review

Sign in to review this change.
2 files changed +48 −2
src/http/api.ts +4 −2
@@ -2247,6 +2247,7 @@ export function apiRoutes(router: Router<Handler>): void {
22472247 // of its own first (`strangers.ts`): `git grep` over fifty repositories
22482248 // is not a request to answer as fast as anyone can send it.
22492249 router.add("GET", "/api/v1/search", async (ctx) => {
2250 notePhase(ctx.request, "session", takeSessionTime(ctx.request));
22502251 const q = ctx.url.searchParams;
22512252 const kind = searchKind(q.get("kind"));
22522253 const query = q.get("q") ?? "";
@@ -2261,14 +2262,15 @@ export function apiRoutes(router: Router<Handler>): void {
22612262 return refused;
22622263 }
22632264 try {
2264 return json(
2265 await search(ctx.app, ctx.auth.user, {
2265 const found = await timePhaseAsync(ctx.request, "search", () =>
2266 search(ctx.app, ctx.auth.user, {
22662267 q: query,
22672268 kind,
22682269 ...(q.has("limit") ? { limit: Number(q.get("limit")) } : {}),
22692270 live: q.get("live") === "1" || q.get("live") === "true",
22702271 }),
22712272 );
2273 return timePhase(ctx.request, "render", () => json(found));
22722274 } finally {
22732275 held?.release();
22742276 }
test/api-search-timing.test.ts added +44
@@ -0,0 +1,44 @@
1 /** The API's search names its Server-Timing phases (#3919). */
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 { quietLogs } from "./helpers/globals.ts";
9
10 quietLogs();
11
12 let dataDir: string;
13 let app: App;
14 let servers: Servers;
15 const cells = process.env["FORGE_CELLS"];
16
17 beforeAll(async () => {
18 process.env["FORGE_CELLS"] = "off";
19 dataDir = await mkdtemp(join(tmpdir(), "forge-api-search-timing-"));
20 app = createApp({ dataDir, port: 0 });
21 servers = await serve(app);
22 });
23
24 afterAll(async () => {
25 await servers.stop();
26 app.close();
27 if (cells === undefined) delete process.env["FORGE_CELLS"];
28 else process.env["FORGE_CELLS"] = cells;
29 await rm(dataDir, { recursive: true, force: true });
30 });
31
32 async function phases(path: string): Promise<{ status: number; names: string[]; body: string }> {
33 const res = await fetch(`${servers.url}${path}`);
34 const body = await res.text();
35 const names = (res.headers.get("server-timing") ?? "").split(", ").map((p) => p.split(";")[0]!);
36 return { status: res.status, names: names.slice(names.indexOf("app") + 1), body };
37 }
38
39 test("the API search names session, search and render in order", async () => {
40 const got = await phases("/api/v1/search?q=forge&kind=repos");
41 expect(got.status).toBe(200);
42 expect(got.names).toEqual(["session", "search", "render"]);
43 expect(typeof JSON.parse(got.body)).toBe("object");
44 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs