252 lines · 10.0 KB
import { env, WorkflowEntrypoint } from "cloudflare:workers";
import { numberVar } from "../limits";
import type { WorkflowEvent, WorkflowStep } from "cloudflare:workers";
import { all, first, run } from "../db";
import { loadRepoById } from "../repos";
import { emitNotification, emitWebhook, publicUrl } from "../events/emit";
import { completeJob, isCloudJob, runnerStub } from "./jobs";
import type { WorkflowJobRow, WorkflowRunRow } from "./jobs";
import type { CompiledJob } from "./compile";
import type { Conclusion } from "~/lib/types";

export type CiRunParams = { runId: string };

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

const WAIT_TIMEOUT = "5 minutes";
const MAX_ITERATIONS = 1000;
const QUEUE_DEADLINE_MS = 24 * 60 * 60 * 1000;
const DAY_MS = 24 * 60 * 60 * 1000;
const MINUTE_MS = 60 * 1000;
const CAPACITY_RETRY = "1 minute";
const DEFAULT_JOBS_PER_OWNER = 4;
const DEFAULT_MINUTES_PER_DAY = 600;
const CLOUD_RUNS_ON = ['["cloudflare"]', '["ubuntu-latest"]'];

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

/**
 * Daily Container-minute budget per owner. 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.