/ concept-collection / turing-surface-cache
concept-collection / turing-surface-cache
turing-surface-cache / src / cache / fillWalk.ts
89 lines · 3.3 KBCodeBlameHistory
2 * Working through the parameter space on an idle machine: for every target of
3 * the walk (src/cache/autoWalk.ts), skip whatever the cloud already has and
4 * compute and contribute the rest, until stopped.
5 *
6 * The loop is short but its rules matter, and they are the same in the page
7 * and on the command line. A skip costs one HEAD, and only the longest end
8 * time need be asked about, since a run reaching it emits every shorter one on
9 * the way. One bad combination — a compile that fails, a solution that blows
10 * up — is reported and stepped over rather than ending the walk. And every
11 * target goes through the ordinary local run, warm start, background uploads,
12 * divergence guard and all.
13 */
14import type { AutoTarget } from './autoWalk.ts';
15import { isCached, lookupFor } from './client.ts';
16import { runSpec, type RunEvents, type RunOutcome } from './runSpec.ts';
17import type { SolverSession } from './solver.ts';
18import type { CacheSpec } from './spec.ts';
20export interface FillCounts {
21 computed: number;
22 skipped: number;
23 failed: number;
26export interface FillEvents extends RunEvents {
27 /** A target is being considered; its cache status is not known yet. */
28 onTarget?(target: AutoTarget, spec: CacheSpec): void;
29 /** Already in the cloud — nothing to do. */
30 onCached?(target: AutoTarget, spec: CacheSpec): void;
31 /** Not cached: the run is about to start. */
32 onComputing?(target: AutoTarget, spec: CacheSpec): void;
33 onOutcome?(target: AutoTarget, spec: CacheSpec, outcome: RunOutcome): void;
34 onFailure?(target: AutoTarget, spec: CacheSpec, error: unknown): void;
35 /** True ends the walk at the next target boundary. */
36 walkStopped?(): boolean;
39export interface FillOptions {
40 targets: AutoTarget[];
41 solver: SolverSession;
42 adapter: string;
795cdccMove the run and the walk out of the pageJeremy Magland 44 apiKey(): string;
45 /**
46 * Take the selection to this target and hand back the spec to compute. The
47 * page uses this to drive its own dropdowns and URL, so that what is on
48 * screen always says what is being computed.
49 */
50 beforeTarget(target: AutoTarget): CacheSpec | Promise<CacheSpec>;
51 events?: FillEvents;
54export async function fillWalk(opts: FillOptions): Promise<FillCounts> {
55 const ev = opts.events ?? {};
56 const counts: FillCounts = { computed: 0, skipped: 0, failed: 0 };
57 for (const target of opts.targets) {
58 if (ev.walkStopped?.()) break;
59 const spec = await opts.beforeTarget(target);
60 ev.onTarget?.(target, spec);
61 try {
62 if (await isCached(await lookupFor(spec))) {
63 counts.skipped++;
64 ev.onCached?.(target, spec);
65 continue;
66 }
67 if (ev.walkStopped?.()) break;
68 ev.onComputing?.(target, spec);
69 await opts.solver.apply(spec);
70 const outcome = await runSpec({
71 solver: opts.solver,
72 spec,
73 adapter: opts.adapter,
b0546a9Fix the command line's file writing, and how it gets updatedJeremy Magland 74 runtime: opts.runtime,
795cdccMove the run and the walk out of the pageJeremy Magland 75 apiKey: opts.apiKey,
76 events: ev,
77 });
78 if (outcome.kind === 'done') counts.computed++;
79 else if (outcome.kind === 'diverged') counts.failed++;
80 ev.onOutcome?.(target, spec, outcome);
81 if (outcome.kind === 'abandoned') break;
82 } catch (e) {
83 // One bad combination must not end the walk: report it and move on.
84 counts.failed++;
85 ev.onFailure?.(target, spec, e);
86 }
87 }
88 return counts;