Public: anyone can read this; the crew can change it.
Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:3hv73alvgf is past its budget: trevato/forge: "GET /apps/open names its phases and answers within its budget" failed on 3 pulls in the last hour — the… #7515
Check · Review · Land · Live done — Landed and live in production.
torque/forge:torque/7490-sentinel-shared-01m23vygyffx5hg2f5vm8r74 → main 1 commit fork
4 files
changed +15
−8
src/web/pages/apps.ts +2
| @@ -48,6 +48,7 @@ import { | ||
| 48 | 48 | import type { User } from "../../core/users.ts"; |
| 49 | 49 | import { safeBack, type Ctx } from "../../http/context.ts"; |
| 50 | 50 | import { |
| 51 | nameFrame, | |
| 51 | 52 | notePhase, |
| 52 | 53 | takeSessionTime, |
| 53 | 54 | timePhase, |
| @@ -716,6 +717,7 @@ export function previewCard(ctx: Ctx, repo: Repo, pull: Pull): Html { | ||
| 716 | 717 | * theirs, nothing else is. |
| 717 | 718 | */ |
| 718 | 719 | export function appsOpen(ctx: Ctx): Response { |
| 720 | nameFrame(ctx.request); | |
| 719 | 721 | notePhase(ctx.request, "session", takeSessionTime(ctx.request)); |
| 720 | 722 | return timePhase(ctx.request, "render", () => appsOpenResponse(ctx)); |
| 721 | 723 | } |
src/web/pages/cloud.ts +2 −1
| @@ -24,7 +24,7 @@ import { | ||
| 24 | 24 | type CloudAccount, |
| 25 | 25 | type CloudRead, |
| 26 | 26 | } from "../../core/cloud_account.ts"; |
| 27 | import { notePhase, takeSessionTime, timePhase, timePhaseAsync } from "../../core/route_timing.ts"; | |
| 27 | import { nameFrame, notePhase, takeSessionTime, timePhase, timePhaseAsync } from "../../core/route_timing.ts"; | |
| 28 | 28 | import type { Ctx } from "../../http/context.ts"; |
| 29 | 29 | import { notFoundPage, settingsLayout, signInFirst } from "../chrome.ts"; |
| 30 | 30 | import { field, readForm } from "../form.ts"; |
| @@ -218,6 +218,7 @@ export async function cloudAudit(ctx: Ctx): Promise<Response> { | ||
| 218 | 218 | |
| 219 | 219 | // GET /settings/cloud/audit |
| 220 | 220 | export function cloudAuditPage(ctx: Ctx): Response { |
| 221 | nameFrame(ctx.request); | |
| 221 | 222 | notePhase(ctx.request, "session", takeSessionTime(ctx.request)); |
| 222 | 223 | const denied = requireAdmin(ctx); |
| 223 | 224 | if (denied) return timePhase(ctx.request, "render", () => denied); |
src/web/pages/org.ts +2 −1
| @@ -33,7 +33,7 @@ import { LIST_LIMIT_MAX } from "../../core/issues.ts"; | ||
| 33 | 33 | import { listReposByOwner, type Repo } from "../../core/repos.ts"; |
| 34 | 34 | import { getUserByName, hiddenFrom, type User } from "../../core/users.ts"; |
| 35 | 35 | import type { Ctx } from "../../http/context.ts"; |
| 36 | import { notePhase, takeSessionTime, timePhase, timePhaseAsync } from "../../core/route_timing.ts"; | |
| 36 | import { nameFrame, notePhase, takeSessionTime, timePhase, timePhaseAsync } from "../../core/route_timing.ts"; | |
| 37 | 37 | import { notFoundPage, pageHead, signInFirst } from "../chrome.ts"; |
| 38 | 38 | import { field, readForm, type Form } from "../form.ts"; |
| 39 | 39 | import { html, when, type Html } from "../html.ts"; |
| @@ -457,6 +457,7 @@ function orgForm(ctx: Ctx, value: string, error?: string): Response { | ||
| 457 | 457 | |
| 458 | 458 | // GET /organizations/new |
| 459 | 459 | export function newOrgPage(ctx: Ctx): Response { |
| 460 | nameFrame(ctx.request); | |
| 460 | 461 | notePhase(ctx.request, "session", takeSessionTime(ctx.request)); |
| 461 | 462 | return timePhase(ctx.request, "render", () => |
| 462 | 463 | ctx.auth.user ? orgForm(ctx, "") : signInFirst(ctx), |
test/cloud-org-apps-timing.test.ts +9 −6
| @@ -46,10 +46,12 @@ afterAll(() => { | ||
| 46 | 46 | }); |
| 47 | 47 | |
| 48 | 48 | // /apps/open with no host is the answer a stranger gets: session, then render. |
| 49 | // `route` and `compress` are the server's own work around the handler: named, | |
| 50 | // the accounting no longer hangs on how long a loaded machine takes outside it. | |
| 49 | 51 | const PAGES: [string, string[]][] = [ |
| 50 | ["/settings/cloud/audit", ["session", "audit", "render"]], | |
| 51 | ["/organizations/new", ["session", "render"]], | |
| 52 | ["/apps/open", ["session", "render"]], | |
| 52 | ["/settings/cloud/audit", ["route", "session", "audit", "render", "compress"]], | |
| 53 | ["/organizations/new", ["route", "session", "render", "compress"]], | |
| 54 | ["/apps/open", ["route", "session", "render", "compress"]], | |
| 53 | 55 | ]; |
| 54 | 56 | |
| 55 | 57 | for (const [path, names] of PAGES) |
| @@ -77,13 +79,14 @@ for (const [path, names] of PAGES) | ||
| 77 | 79 | |
| 78 | 80 | // Signed out, the redirect to sign-in is still a named phase. |
| 79 | 81 | for (const path of ["/settings/cloud/audit", "/organizations/new"]) |
| 80 | test(`signed-out GET ${path} names session and render`, async () => { | |
| 82 | test(`signed-out GET ${path} names route, session, render and compress`, async () => { | |
| 81 | 83 | const res = await fetch(`${servers.url}${path}`, { redirect: "manual" }); |
| 82 | 84 | await res.text(); |
| 83 | 85 | expect(res.status).toBe(303); |
| 84 | 86 | const parts = (res.headers.get("server-timing") ?? "").split(", "); |
| 85 | 87 | const dur = (n: string) => Number(parts.find((p) => p.startsWith(`${n};`))!.split("dur=")[1]); |
| 86 | for (const name of ["session", "render"]) | |
| 88 | const names = ["route", "session", "render", "compress"]; | |
| 89 | for (const name of names) | |
| 87 | 90 | expect(parts.find((p) => p.startsWith(`${name};`))).toMatch(/^[a-z]+;dur=\d+\.\d$/); |
| 88 | expect(Math.abs(dur("app") - dur("session") - dur("render"))).toBeLessThan(1.5); | |
| 91 | expect(Math.abs(dur("app") - names.reduce((sum, n) => sum + dur(n), 0))).toBeLessThan(1.5); | |
| 89 | 92 | }); |
new above
offline