211 lines · 8.0 KB
import { env } from "cloudflare:workers";
import { numberVar } from "../limits";
import { all, first, run } from "../db";
import { completeJob, isCloudJob, runnerStub } from "./jobs";
import type { WorkflowJobRow, WorkflowRunRow } from "./jobs";
import { gateJob } from "./deployments";
import { recompileJob } from "./recompile";
import { CLOUD_RUNS_ON_VALUES, cloudRunsOnPlaceholders, runnerWeightSql } from "./runner-sizes";
import type { CompiledJob } from "./compile";
import type { Conclusion } from "~/lib/types";

export type JobState = {
  id: string;
  key: string;
  baseKey: string;
  needs: string[];
  runsOn: string[];
  status: string;
  conclusion: Conclusion | null;
  cloud: boolean;
  runIfOk: boolean;
  runIfFailed: boolean;
  row: WorkflowJobRow;
};

export type TickResult = { active: number; dispatched: number; deferred: number; gated: number; wakeAt: number | null };

const QUEUE_DEADLINE_MS = 24 * 60 * 60 * 1000;
const REVIEW_DEADLINE_MS = 72 * 60 * 60 * 1000;
const DAY_MS = 24 * 60 * 60 * 1000;
const MINUTE_MS = 60 * 1000;
const DEFAULT_JOBS_PER_OWNER = 4;
const DEFAULT_MINUTES_PER_DAY = 600;

type OwnerQuota = { ownerId: string; quotaExceeded: boolean; createdAt: number };

/**
 * Daily Container-minute budget per owner, weighted by runner size. Running and queued jobs are charged their
 * full timeout up front so an owner just under budget can't start a burst of long jobs.
 */