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.
Build one image-file digest once per runner process
77056ba834ba243104726b91e7ff19498d4e8337 · Keenan Nemetz · 3d ago · parent 18c559ea
Build one image-file digest once per runner process Two slots leased jobs that name the same image-file and both built it: the same bytes, the same tag, twice the CPU and twice the disk, with two runtimes racing to tag the result. The first slot now builds it and the others wait on the same answer, which is shared by the process rather than by the session, because that is what --jobs is. Waiting is not free: a build can run for half an hour, and a runner that stops heartbeating loses the run it is holding. So a waiter heartbeats on the same beat its own build would have, and stops if the lease goes away or a maintainer cancels the run. A failed build fails the jobs waiting on it, since the same definition would fail the same way. Two runner processes sharing a --dir can still both build the digest. That is waste, not damage: the definition is pinned by digest, so both builds produce the same image under the same tag, and serialising that too would mean a lock file per digest beside the caches. Refs: 01M6SCWCSX39QXS38QAHQSMVGX (#216)
ci/agent/sandbox.go +7−1
| @@ -32,11 +32,16 @@ import ( | |||
| 32 | 32 | ) | |
| 33 | 33 | ||
| 34 | 34 | // runnerBox is the validated container settings plus the identity this runner | |
| 35 | // process uses to find containers a killed predecessor left behind. | ||
| 35 | // process uses to find containers a killed predecessor left behind, and the builds | ||
| 36 | // it has in flight. | ||
| 36 | 37 | type runnerBox struct { | |
| 37 | 38 | container.Config | |
| 38 | 39 | id string | |
| 39 | 40 | pid int | |
| 41 | // builds is shared by every slot in the process, so two jobs that name the same | ||
| 42 | // image-file build it once. Nil means the caller never validated these options, | ||
| 43 | // which only a test does. | ||
| 44 | builds *imageBuilds | ||
| 40 | 45 | } | |
| 41 | 46 | ||
| 42 | 47 | // containerOptions validates the runner's container settings and fills in the | |
| @@ -64,6 +69,7 @@ func containerOptions(opts Options, cache string) (runnerBox, error) { | |||
| 64 | 69 | Config: cfg, | |
| 65 | 70 | id: fmt.Sprintf("%x", sum[:6]), | |
| 66 | 71 | pid: os.Getpid(), | |
| 72 | builds: &imageBuilds{}, | ||
| 67 | 73 | }, nil | |
| 68 | 74 | } | |
| 69 | 75 | ||