Skip to content
76 linesCodeBlameRaw
1/**
2 * The machine catalogue: every label a workflow job can ask for in
3 * `runs-on`, and the machine g1t runs it on. Mirrors
4 * `g1t_contracts::actions::INSTANCE_TYPES` row for row (a Rust test reads
5 * this file), and services/runner/wrangler.jsonc gives each row's class its
6 * instance type (a runner test holds them together). Each machine is a
7 * named Cloudflare Containers instance type: the standard machine is
8 * standard-3 (2 vCPU, 8 GiB, 16 GB of disk), `g1t-2core` is kept as a name
9 * of it so workflows that ask for it keep working, and `g1t-4core` is
10 * standard-4 (4 vCPU, 12 GiB, 20 GB). See CONTRIBUTING.md, "Adding a
11 * machine size".
12 */
13export type InstanceType = {
14 /** The `runs-on` label, or `standard` for the default. */
15 label: string;
16 /**
17 * The machine, as it is billed and reported (`2-core`): runner minutes
18 * are counted by machine, so a label renamed or pointed at another
19 * machine leaves the history where it was. Never reused.
20 */
21 machine: string;
22 /** The runner's Durable Object class that runs it, one per label. */
23 sandboxClass: string;
24 /** The named Containers instance type its class runs on. */
25 container: string;
26 vcpu: number;
27 memoryGib: number;
28 diskGb: number;
29 /**
30 * What a minute of it is charged, in millionths of a dollar: a job is
31 * charged its minutes, rounded up, at this rate (`runnerMinutes`).
32 */
33 microsPerMinute: number;
34};
35
36/** Every label a job can ask for, the default first. One row a line, as the Rust table's test reads them. */
37export const INSTANCE_TYPES: readonly InstanceType[] = [
38 { label: "standard", machine: "2-core", sandboxClass: "AttemptSandbox", container: "standard-3", vcpu: 2, memoryGib: 8, diskGb: 16, microsPerMinute: 4000 },
39 // The standard machine under the name it had when it was larger.
40 { label: "g1t-2core", machine: "2-core", sandboxClass: "Sandbox2Core", container: "standard-3", vcpu: 2, memoryGib: 8, diskGb: 16, microsPerMinute: 4000 },
41 { label: "g1t-4core", machine: "4-core", sandboxClass: "Sandbox4Core", container: "standard-4", vcpu: 4, memoryGib: 12, diskGb: 20, microsPerMinute: 7000 },
42];
43
44/** The default: what `ubuntu-latest` and every other hosted label get. */
45export const STANDARD_INSTANCE: InstanceType = INSTANCE_TYPES[0]!;
46
47/** An instance type by its label; the standard one for anything else. */
48export function instanceNamed(label: string | null | undefined): InstanceType {
49 const wanted = label?.trim().toLowerCase();
50 return INSTANCE_TYPES.find((instance) => instance.label === wanted) ?? STANDARD_INSTANCE;
51}
52
53/** The machines, once each, in the catalogue's order: the first row of each. */
54export function machines(): InstanceType[] {
55 return INSTANCE_TYPES.filter((instance, at) => INSTANCE_TYPES.findIndex((other) => other.machine === instance.machine) === at);
56}
57
58/** A machine by its key (`2-core`); null when there is none. */
59export function machineNamed(machine: string): InstanceType | null {
60 return INSTANCE_TYPES.find((instance) => instance.machine === machine) ?? null;
61}
62
63/** Its price as a multiple of the standard machine's. */
64export function priceScale(instance: InstanceType): number {
65 return instance.microsPerMinute / STANDARD_INSTANCE.microsPerMinute;
66}
67
68/** `2 vCPU, 8 GiB, 16 GB`. */
69export function machineSize(instance: InstanceType): string {
70 return `${instance.vcpu} vCPU, ${instance.memoryGib} GiB, ${instance.diskGb} GB`;
71}
72
73/** The minutes a job is charged for: its time rounded up to the minute, at least 1 for a job that ran. */
74export function runnerMinutes(seconds: number): number {
75 return seconds <= 0 ? 0 : Math.ceil(seconds / 60);
76}