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.

Let a job budget its whole run

e7aa0785cb69ace8c1338cc0b924113ea52a7abb · Keenan Nemetz · 6d ago · parent 2bc0ae74

Let a job budget its whole run

A step was capped at an hour and a job was not capped at all, so 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 — a session, a soak test, a
slow suite — could not be expressed, because the only clock was per step and its
ceiling was an hour.

A job may now declare `timeout: 2h`: a wall clock its 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. A budget spent before a step starts stops the
job there instead of running the step on its own cap.

The budget is optional, pinned with the run, and spent by a local run the same
way, so nothing changes for a workflow that does not declare one. The step
ceiling rises from one hour to four to make a single long step possible; the
default stays ten minutes. The image build is not charged to the budget — it has
its own cap, so a slow pull cannot eat the time the steps were given.

A step timeout longer than its job's budget is refused at push time: the budget
would end first, so the step could never use what it asked for.

Closes #161.

# Conflicts:
#	ci/agent/agent.go
#	cmd/vole/workflowrun.go
#	docs/reference/workflow-reference.md

docs/reference/workflow-reference.md +49−5

@@ -33,8 +33,9 @@ Unknown keys are rejected. A workflow is validated when it is pushed and again b
33 33 | Maximum schedules | 5 |
34 34 | Maximum manual inputs | 10 |
35 35 | Maximum event payload | 64 KiB |
36 | Default step timeout | 10 minutes |
37 | Maximum step timeout | 1 hour |
36 | Default step timeout | 10 minutes, when the job has no budget |
37 | Maximum step timeout | 4 hours |
38 | Maximum job timeout | 4 hours |
38 39
39 40 ## Top-level fields
40 41
@@ -413,6 +414,7 @@ letter. At least one job is required.
413 414 | `network` | `none` or `bridge` | no | the runner's setting | Whether the job's container has a network. |
414 415 | `secrets` | string or list of strings | no | none | Repository secrets the job reads, by name. Each name is also the variable a step finds it in. |
415 416 | `env` | mapping | no | none | Environment every step of the job runs with. |
417 | `timeout` | duration string | no | none | Wall clock the job's steps share. |
416 418 | `steps` | list | yes | — | Commands the job runs. At least one is required. |
417 419 | `artifacts` | list | no | none | Files the job publishes. |
418 420 | `pages` | mapping | no | none | Directory published as the repository's website. |
@@ -643,6 +645,44 @@ best effort, and worth knowing exactly:
643 645 - an artifact, a site file or a release attachment is stored as the step wrote it,
644 646 so a secret a step writes to a file it publishes is published.
645 647
648 ### `timeout`
649
650 A wall-clock budget for the job's steps, instead of a cap on each step separately:
651
652 ```yaml
653 jobs:
654 test:
655 image: golang:1.27-bookworm
656 timeout: 2h
657 steps:
658 - run: go test ./...
659 - run: go vet ./...
660 ```
661
662 The budget starts with the first step and is spent in order. A step that declares its
663 own `timeout:` is still cut short when the budget ends first, and a step that declares
664 none runs with whatever is left, so one long step is enough to say:
665
666 ```yaml
667 jobs:
668 agent:
669 image-file: agent
670 timeout: 4h
671 steps:
672 - run: run-the-session
673 ```
674
675 When the budget is spent before a step starts, that step does not run and the job
676 fails, with one line in the log saying so. The field is optional: without it each step
677 is bounded by its own timeout, which is how a workflow worked before the field
678 existed.
679
680 The image build is not part of the budget. It has its own cap, so a slow pull cannot
681 eat the time the steps were given.
682
683 `timeout` is at most 4 hours, and a step whose own timeout is longer than the job's is
684 refused at push time: the budget would end first, so the step could never use it.
685
646 686 ### `steps`
647 687
648 688 A non-empty list of shell steps, at most 100. Steps run in order. A step that exits
@@ -657,7 +697,7 @@ container and filesystem with the other steps in the same job.
657 697 |---|---|---|---|---|
658 698 | `name` | string | no | first line of `run` | Display name in the log. |
659 699 | `run` | string | yes | — | Shell command executed with `/bin/sh -c`. |
660 | `timeout` | duration string | no | `10m` | Maximum time for this step. |
700 | `timeout` | duration string | no | the job's remaining budget, or `10m` | Maximum time for this step. |
661 701
662 702 ```yaml
663 703 steps:
@@ -671,7 +711,11 @@ trimmed; when omitted it is derived from the first line of `run`, shortened to 6
671 711 characters.
672 712
673 713 `timeout` uses Go duration syntax (`90s`, `10m`, `1h`). It must be positive and no
674 more than `1h`. When a step times out, the job fails and its container is stopped.
714 more than 4 hours, and it may not be longer than the job's own `timeout` when that is
715 declared. When a step times out, the job fails and its container is stopped.
716
717 A step that declares no timeout of its own runs with the rest of the job's budget,
718 or 10 minutes when the job has no budget. See the job's [`timeout`](#timeout), which is the budget the step runs inside.
675 719
676 720 ### `artifacts`
677 721
@@ -784,7 +828,7 @@ It does not support:
784 828 - expressions or `${{ }}` contexts; the shell is the expression language and the
785 829 event file is the context. See [Context and expressions](#context-and-expressions).
786 830 - service containers, cache keys, or artifact downloads between jobs
787 - job-level timeouts, concurrency groups, or cancel-in-progress
831 - concurrency groups, or cancel-in-progress
788 832 - workflow-level `env`, working directories, or shells; `env` is per job and every
789 833 step runs through `/bin/sh -c` in the checkout
790 834 - reusable workflows or composite actions (`uses:`); shell in an image is the