import { cloudRunnerSize } from "../ci/runner-sizes";
import type { RunnerBinding } from "../ci/runner-sizes";
import { all } from "../db";
import type { MeterId } from "~/lib/meters";
import { recordUsage } from "./record";
const METER_FOR_BINDING: Record<RunnerBinding, MeterId> = {
RUNNER: "compute.runner",
RUNNER_LARGE: "compute.runner_large",
RUNNER_XLARGE: "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;
sourceRepoId: string;
}): Promise<void> {
const seconds = jobSeconds(input.startedAt, input.completedAt);
const steps = await all<{ count: number }>(