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.

#218

Run several jobs at once with --jobs

merged · by keenan 2d ago · merged into main at 18c559ea by keenan 2d ago

keenan opened this 2d ago

What

Slice 2 of #216: vole runner --jobs N.

  • N slots in one process. Each owns a session and runs at most one job; the server already leases per session and claims it with a conditional update, so nothing on that side changed. Options.Jobs, --jobs (default 1, < 1 refused), RUNNER_JOBS in the first-boot renderer.
  • Process work happens once. Directories, cache bounds, the leftover sweep, the connections, and the --repos check are done before any slot starts. The slots share the cache root, the saved checkouts and the images; they differ only in the session they lease on.
  • Failure policy. A job this runner refuses stops every slot and the process reports why — reconnecting would ask the same instance the same question. A lost connection is the slot’s own: it reconnects with a doubling delay (2s → 30s) and the job it was running is requeued when its lease expires. --once keeps the one-shot shape: a failure ends the process, and the scheduler decides about a retry.
  • The log stream belongs to the job. It was a field on the session (s.stream), which only worked because a session never had two jobs. It is now created in run and passed to finish.
  • A halted slot stops leasing. A slot that is told to stop finishes the job it is on and reports it, then exits.

Tests

  • TestSeveralSessionsLeaseDifferentJobs: four sessions on one account lease four distinct runs, each on attempt 1. (Writing it found that enqueue is idempotent per (repo, ref, sha, workflow, job), so four identical enqueues are one run — the test varies the job name and says why.)
  • TestARepositoryAtItsCapLeavesTheSlotsForOthers: max_jobs_per_repo = 2 with three sessions leases exactly two.
  • TestASlotRefusesAJobItWillNotRun / TestAnEmptyLeaseIsNotARefusal: the refusal/reconnect classification, over a pipe instead of a server.
  • TestNextDelayDoublesAndCaps, TestSleepStopsWhenTheContextEnds.
  • TestRunnerRejectsAJobCountBelowOne: 0, -1 and a non-number are refused before anything connects.

Verification

gofmt -l ., go vet ./..., go test -tags sqlite_fts5 ./... clean, and vole workflow run verify ok (format, vet, build, licenses, govulncheck, packages, deployment files, links, go test -race -count=1 ./...). Also scripts/check-deploy.py against the rendered first-boot file, which now asserts the job count survives rendering.

Deliberately not here

  • SIGTERM does not drain. Today the process is killed mid-step; with slots that is N jobs instead of one. Draining needs signal.NotifyContext plus a way to cut a parked lease short, and a second signal has to still kill it — worth its own change, and the one thing I would do next.
  • The image-build singleflight (two slots building the same image-file digest) is slice 3, with the remaining docs.
  • Presence is N rows per machine on the runners page, and an idle slot holds a connection against ssh_max_connections. Both are documented; grouping rows by machine is a UI decision, not a blocker.

Docs

docs/runner.md gains “Running several jobs at once” (session per slot, per-job container limits, /cache shared with the same repository’s own jobs, connections), docs/cli.md and packaging/runner.env explain the flag, docs/deploy/runner.md covers RUNNER_JOBS.

Refs #216 (does not close it).

Discussion (0)

No discussion yet.