Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

#163

Let a job budget its whole run

merged · by keenan 6d ago · merged into main at e7aa0785 by keenan 6d ago

keenan opened this 6d ago

What

A job can budget its whole run:

jobs:
  agent:
    image-file: agent
    timeout: 4h
    steps:
      - run: run-the-session

The budget is a wall clock the steps share, starting with the first step. A step that declares its own timeout: is cut short when the budget ends first, and a step that declares none runs with whatever is left — so one long step needs only the job’s number. When the budget is spent before a step starts, the job stops there with one line in the log instead of running that step on its own cap.

The field is optional, so a workflow that does not declare one behaves exactly as before: each step keeps its own cap.

Why

Two gaps in one. A job of several slow steps held a runner for as long as they took, with no number saying what the job was allowed to spend. And one long step could not be expressed at all: the only clock was per step and its ceiling was an hour, which is why a coding-agent session or a soak test could not live in a workflow. This closes the “job-level timeout” item in #138 §3 and removes it from the reference’s list of things a workflow cannot express.

Shape

  • Format (ci/workflow.go): Job.Timeout, validated at push (positive, ≤ 4 hours), and a step timeout longer than the job’s budget is refused with the reason. MaxTimeout rises from one hour to four; DefaultTimeout stays at ten minutes.
  • One rule for the limit (ci.StepLimit, ci.BudgetLeft): the step’s own timeout, clamped to what is left of the budget, or the remaining budget when the step declares none. The runner and the local run both call it, so the two cannot drift.
  • Queue (ci/runs): the budget is pinned with the run in an additive column, like the steps and the labels, so editing the workflow after the push cannot change what a queued job is allowed to spend.
  • Runner (ci/agent): starts the clock with the first step (an image build has its own cap and is not charged), cuts each step to the limit, and reports a spent budget as a failed step so the record keeps its shape.
  • Local run (cmd/vole): spends the budget the same way and fails with the same message.
  • Docs: the limits table, the job field table, a timeout section with the image-build note, the step table’s default, and the removal of “job-level timeouts” from what a workflow cannot express.

Not in this change

Stopping a job that is already running is #162. It is a queue and runner-protocol change (a cancel marker, a heartbeat reply field, a finished attempt that stays canceled) rather than a format one, and it reviews better on its own.

Raising the ceiling to four hours is a judgement call: it covers a long agent session with room to spare, and a workflow that declares a budget above it is refused rather than allowed to hold a runner for a day.

Checks

  • go build ./..., go vet ./..., gofmt -l . clean.
  • vole workflow run verify passes in the pinned image (format, vet, build, licenses, govulncheck, packages, links, race tests).
  • New tests: TestJobTimeoutIsParsedAndValidated and TestStepLimit in ci (including a past deadline being spent rather than unlimited), TestTimeoutIsPinnedAtEnqueue, the runner’s revalidation of a bad budget, TestWorkflowRunSharesAJobBudget and TestWorkflowRunStopsWhenTheJobBudgetIsSpent in the local run.

Closes #161.

Discussion (0)

No discussion yet.