Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 1 | /** |
| 2 | * How long the site waits on a service before it gives up. Nothing on | |
| 3 | * Workers ends a subrequest that stops answering: the page waits as long | |
| 4 | * as the visitor does, so a service stuck on one call holds the page on | |
| 5 | * its loading bar for good. With a deadline it fails instead, as an error | |
| 6 | * the page can draw and the next click can get past. | |
| 7 | */ | |
| 8 | ||
| 9 | /** A read: no page should wait longer than this on one service call. */ | |
| 10 | export const READ_DEADLINE_MS = 15_000; | |
| 11 | ||
| 12 | /** A write: some do real work (a merge, a commit), so they get longer. */ | |
| 13 | export const WRITE_DEADLINE_MS = 60_000; | |
| 14 | ||
| 15 | /** Reads that do real work inline the first time, or walk history. */ | |
| 16 | export const SLOW_READ_DEADLINE_MS = 60_000; | |
| 17 | ||
| 18 | /** Jobs a person starts and waits on: an import, a model's draft, a computer waking. */ | |
| 19 | export const LONG_DEADLINE_MS = 600_000; | |
| 20 | ||
| 21 | /** | |
| 22 | * Reads that can take longer than `READ_DEADLINE_MS` and still be right, | |
| 23 | * by service binding and method. Cut off, their work is lost and starts | |
| 24 | * again on the next visit, so they get the time to finish. | |
| 25 | */ | |
| 26 | const SLOW_READS = new Set([ | |
| 27 | // A repository's first look runs its dependency scan inline (services/security/src/deps.rs). | |
| 28 | "security overview", | |
| 29 | "security dependency_graph", | |
| 30 | "security sbom", | |
| 31 | // Walks up to 400 commits, reading trees and blobs one after another (services/repos/src/blame.rs). | |
| 32 | "repos blame", | |
| 33 | // Up to 2,500 store reads per call (services/repos/src/last_commits.rs). | |
| 34 | "repos last_commits", | |
| 35 | ]); | |
| 36 | ||
| 37 | /** | |
| 38 | * Writes that run for minutes and still finish: copying a repository in, | |
| Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them. | 39 | * a scan over many repositories. |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 40 | */ |
| 41 | const LONG_CALLS = new Set([ | |
| 42 | "repos create", | |
| 43 | "integrations github_import", | |
| 44 | "security dry_run_pattern", | |
| 45 | "security rescan", | |
| 46 | "security check_updates", | |
| 47 | "artifacts add_repo_space", | |
| 48 | ]); | |
| 49 | ||
| 50 | /** How long a call to `service`'s `method` may take; `writes` as lib/perf.ts `mayWrite` says. */ | |
| 51 | export function deadlineFor(service: string, method: string, writes: boolean): number { | |
| 52 | const call = `${service} ${method}`; | |
| 53 | if (LONG_CALLS.has(call)) return LONG_DEADLINE_MS; | |
| 54 | if (SLOW_READS.has(call)) return SLOW_READ_DEADLINE_MS; | |
| 55 | return writes ? WRITE_DEADLINE_MS : READ_DEADLINE_MS; | |
| 56 | } | |
| 57 | ||
| 58 | /** What a call past its deadline throws. */ | |
| 59 | export class DeadlineExceeded extends Error { | |
| 60 | constructor(what: string, ms: number) { | |
| 61 | super(`${what} did not answer within ${ms}ms`); | |
| 62 | this.name = "DeadlineExceeded"; | |
| 63 | } | |
| 64 | } | |
| 65 | ||
| 66 | /** | |
| 67 | * `run`'s answer, or a `DeadlineExceeded` after `ms`. `run` is handed a | |
| 68 | * signal that aborts at the deadline, so the call it makes is cancelled | |
| 69 | * too; `outer`, when given, aborts it sooner. Whatever `run` reads must be | |
| 70 | * read inside it: the deadline ends when it returns. | |
| 71 | */ | |
| 72 | export async function withDeadline<T>( | |
| 73 | what: string, | |
| 74 | ms: number, | |
| 75 | run: (signal: AbortSignal) => Promise<T>, | |
| 76 | outer?: AbortSignal | null, | |
| 77 | ): Promise<T> { | |
| 78 | const controller = new AbortController(); | |
| 79 | let timer: ReturnType<typeof setTimeout> | undefined; | |
| 80 | const expired = new Promise<never>((_, reject) => { | |
| 81 | timer = setTimeout(() => { | |
| 82 | const error = new DeadlineExceeded(what, ms); | |
| 83 | controller.abort(error); | |
| 84 | reject(error); | |
| 85 | }, ms); | |
| 86 | }); | |
| 87 | const stop = () => controller.abort(outer?.reason); | |
| 88 | if (outer?.aborted) stop(); | |
| 89 | else outer?.addEventListener("abort", stop, { once: true }); | |
| 90 | try { | |
| 91 | // Raced as well as aborted: a binding that ignores the signal still lets go. | |
| 92 | return await Promise.race([run(controller.signal), expired]); | |
| 93 | } finally { | |
| 94 | clearTimeout(timer); | |
| 95 | outer?.removeEventListener("abort", stop); | |
| 96 | } | |
| 97 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.