/** * Cloud runner sizes. Each size is its own Container-backed Durable Object class because a Container's * instance type is fixed per class; larger sizes are charged proportionally more Container minutes. */ export type RunnerBinding = "RUNNER" | "RUNNER_LARGE" | "RUNNER_XLARGE"; type RunnerSize = { binding: RunnerBinding; labels: string[]; weight: number; description: string }; export const RUNNER_SIZES: RunnerSize[] = [ { binding: "RUNNER", labels: ["cloudflare", "ubuntu-latest"], weight: 1, description: "standard-1: 1/2 vCPU, 4 GiB", }, { binding: "RUNNER_LARGE", labels: ["cloudflare-large", "ubuntu-latest-4-cores"], weight: 2, description: "standard-2: 1 vCPU, 6 GiB", }, { binding: "RUNNER_XLARGE", labels: ["cloudflare-xlarge", "ubuntu-latest-8-cores"], weight: 4, description: "standard-4: 4 vCPU, 12 GiB", }, ]; export function cloudRunnerSize(runsOn: string[]): RunnerSize | null { if (runsOn.length !== 1) return null; return RUNNER_SIZES.find((size) => size.labels.includes(runsOn[0])) ?? null; } /** The serialized `workflow_jobs.runs_on` values that run on cloud Containers. */ export const CLOUD_RUNS_ON_VALUES = RUNNER_SIZES.flatMap((size) => size.labels.map((label) => JSON.stringify([label]))); /** SQL expression weighting a job's Container minutes by its runner size (`column` is the runs_on column). */ export function runnerWeightSql(column: string): string { const cases = RUNNER_SIZES.filter((size) => size.weight !== 1) .flatMap((size) => size.labels.map((label) => `WHEN '${JSON.stringify([label])}' THEN ${size.weight}`)) .join(" "); return `(CASE ${column} ${cases} ELSE 1 END)`; } export function cloudRunsOnPlaceholders(firstIndex: number): string { return CLOUD_RUNS_ON_VALUES.map((_, index) => `?${firstIndex + index}`).join(", "); }