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/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

Stream run logs over the runner's SSH channel

5ece70a50ebda392626b92bdf29d28bc9b444954 · Keenan Nemetz · 10d ago · parent fdf2340f

Stream run logs over the runner's SSH channel

The runner wrote the log to a temp file and uploaded it as one LFS object
when the job ended, so a running job had no log to read and a log was stored
like a shared artifact even though it belongs to one attempt.

The runner sends 128 KiB chunks over the same runner channel that holds the
lease. The server appends them to data/logs/<repo>/<run>/<attempt>.log and
records the size while the run is still running. The finish record carries
the final size; the server checks the file length, syncs it, and stores the
result. A partial or failed stream leaves no log on the record.

Logs are no longer LFS objects: they are not shared, not content-addressed,
and the web serves the file directly, with range and step slices. GC no
longer treats them as LFS roots.

docs/runner.md +16−15

@@ -86,9 +86,9 @@ instance or kept on the runner, so each of those channels has a bound:
86 86
87 87 - **Logs.** One attempt's log is capped at 32 MiB. Past that the runner keeps the
88 88 first 32 MiB and appends a line saying it was truncated, so a build that loops
89 printing cannot fill the runner's disk or the instance's object store. The log
90 is written straight to a file on the runner and uploaded once at the end; it is
91 not held in memory and nothing is streamed to the server.
89 printing cannot fill the runner's disk or the instance's log directory. The log
90 is written straight to a file on the runner and streamed to the server in chunks
91 while the job runs; it is not held in memory.
92 92 - **Artifacts.** A workflow declares at most 32 patterns, and a run may publish at
93 93 most 256 files totalling 4 GiB. The expanded set is checked before anything is
94 94 uploaded; a pattern that matches a directory tree is the usual way to hit this.
@@ -247,24 +247,25 @@ Admins always count. For everyone else, a maintainer running CI on their laptop
247 247 not turn a required check green. The result is still recorded, and the run page
248 248 says whether it counts.
249 249
250 When a job finishes, the runner uploads its log and sends the attempt's record with
251 its finish message on the same SSH channel that leased the job. Vole checks that the
252 record names the account holding the lease, that it describes the job the queue
253 handed out, and that every log and artifact pointer exists in the store. It then
254 stores the attempt and the run's result in `data/runs.db` in one transaction. A
255 tagged build that publishes release artifacts also pushes those pointers to the
256 `vole` branch after the record is stored.
250 While a job runs, the runner streams its log to the server in chunks over the same
251 SSH channel that leased it. The server writes one file under `data/logs/` and the
252 run page can open it before the job finishes. When the job ends, the runner sends
253 the attempt's record with its finish message; Vole checks that the record names the
254 account holding the lease, that it describes the job the queue handed out, and that
255 every artifact pointer exists in the store. It then stores the attempt and the run's
256 result in `data/runs.db` in one transaction. A tagged build that publishes release
257 artifacts also pushes those pointers to the `vole` branch after the record is
258 stored.
257 259
258 260 The runner did the work, so the runner reports the result. The SSH connection
259 261 identifies the runner, and `data/audit.log` records the decision.
260 262
261 263 ## Logs
262 264
263 The runner uploads the log before reporting the exit code. Vole does not stream
264 live output while a step runs: a log assembled by the server would not be the
265 runner's own record. Once the attempt finishes, the archived object is served
266 directly and supports range requests, so the page does not read a large log into
267 memory.
265 The runner streams the log while the steps run. The server appends each chunk to
266 the attempt's file, and the run page serves that file directly with range requests,
267 so it does not read a large log into memory. The file is complete when the attempt's
268 record is stored.
268 269
269 270 The stored attempt also names each step's byte range in that one log, so the run
270 271 page can show a step's output without downloading the image build and other steps.