import { cloudRunnerSize } from "../ci/runner-sizes";
import type { RunnerBinding } from "../ci/runner-sizes";
import { repoDb } from "../scoped-db";
import type { MeterId } from "~/lib/meters";
import { recordUsage } from "./record";
/** Docker-capable twins bill under their base size's meter: same instance type, so no extra charge. */
const METER_FOR_BINDING: Record<RunnerBinding, MeterId> = {
RUNNER: "compute.runner",
RUNNER_LARGE: "compute.runner_large",
RUNNER_XLARGE: "compute.runner_xlarge",
RUNNER_DIND: "compute.runner",
RUNNER_LARGE_DIND: "compute.runner_large",
RUNNER_XLARGE_DIND: "compute.runner_xlarge",
};
export function runnerMeter(runsOn: string[]): MeterId {
const size = cloudRunnerSize(runsOn);
return size ? METER_FOR_BINDING[size.binding] : "compute.runner_self_hosted";
}
/** Exact runner seconds, never rounded up; a job that never started costs nothing. */
export function jobSeconds(startedAt: number | null, completedAt: number): number {
if (startedAt === null || completedAt <= startedAt) return 0;
return (completedAt - startedAt) / 1000;
}
/**
* Bills a completed job's runner time to the account owning the repository the run executes in. Fork pull
* request runs execute in the base repository, so the base owner pays. Keyed by job id: rerun attempts are
* new job rows, while a duplicate completion of the same job is ignored.
*/
export async function meterCompletedJob(input: {
jobId: string;
runId: string;
accountId: string;
repoId: string;
runsOn: string[];
startedAt: number | null;
completedAt: number;