Expand description
Domain logic and API types shared by the runnerd daemon and its clients.
api and config build everywhere. The host feature (on by default) adds what only the daemon runs: Docker, the
GitHub client, the caches, the scheduler, sizing advice, insights, the job history store and what observes running jobs.
Clients depend on this crate without it, and with the client feature for client, their connection to the daemon.
Modules§
- admission
- Admission by measured peaks: a job’s memory peak and average CPU predicted from the job history (
Predictor), and the history replayed through admission by caps and by predictions, with or without a CPU budget (simulate), to show what each would have done with the same jobs. Pure: no I/O, no clock. - api
- The daemon’s JSON API, version 1: the request and response types every client deserializes, and the
principal a transport authenticates. Plain data only: no I/O, no Docker or GitHub types, no secrets but a
Pairing’s one-time link, which itsDebugleaves out. - buildcache
- The build cache every runner shares (ADR 0052, 0053): the entries of Gradle’s HTTP build cache, and of the other
tools the runner image points at it, kept per repository in a directory of the daemon’s and served to each runner
on a Unix socket of its own, which the runner image forwards to
127.0.0.1. Owns the entries, the size limit, the sockets, and what each runner was served and stored. Which socket a request came in on is who sent it; no job can claim another’s. It never decides whether a job may write: the engine tells it (Writes), from what GitHub says of the job. It never logs a request’s headers, which may carry a tool’s token. - cache
- The warm caches runner containers share and keep between jobs: each profile’s read-only snapshot, each slot’s volume (its layers’ changes and its Docker Engine’s data), the shared pnpm store and Maven repository, and the Docker Hub mirror on the runners’ network. Owns their names, mounts and lifecycle; it never decides when a runner starts, and it never touches a volume a running container uses.
- config
runnerd.toml: the repositories to serve, the runner profiles they use, the shared caches and the host budget they must fit in. Builds without thehostfeature, so clients can read a config; its only I/O is reading the file and askingsystemctlfor a slice’sMemoryMax. It never talks to Docker or GitHub.- docker
- Runner containers through the Docker Engine API: the connection, container, volume and image requests, and the
DockerApitrait the engine and the caches call. It decides nothing about scheduling, and a JIT config only ever reaches a container as a root-only file, never the create request or a log line. - github
- The GitHub REST API as the scheduler and the history need it: queued jobs, a job’s steps, just-in-time runner
configs, repository runners and cancelling a run. Owns the token, conditional requests and rate-limit backoff. It
must never put the token in a log line, a
Debugoutput or an error, and it decides nothing about scheduling. - insights
- Insights from the job history (ADR 0051): jobs that got slower and stayed so, jobs that fail and pass on a re-run, jobs whose memory nears their profile’s cap, jobs that find almost nothing in the build cache, and how long each repository’s jobs wait, this week against the last; and the daily digest. Pure: the daemon reads the history, the config and the clock and passes them in. It sends nothing and changes nothing.
- isolation
- How a runner container is kept from the host while it runs its own Docker Engine. A backend decides only how
the container is created; its name, limits, labels and slice are the same for every backend (
docker). - observe
- What runnerd learns about running jobs without GitHub’s help: CPU, memory and network of each runner container
from its cgroup v2 files and
/proc(metrics), the job a runner took and its log from inside the container (capture), and which runner pulled what through the Docker Hub mirror (mirror). Reads files and parses output; it starts no container, writes nothing to the host, and decides nothing about scheduling. - record
- Records of failed jobs: which runner containers may be kept, the files a record must never hold, which records go
to keep within
[records], and what a shell in a record shows first. Pure functions: the engine (scheduler::engine) commits, lists and removes the images, and the daemon serves the shell. - scheduler
- Which runners to start and stop, as a pure function of queued jobs, slots, warm runners and the memory and CPU
budgets (
plan), how many warm runners each repository wants (warm), and the loop that applies those decisions with GitHub and Docker (engine).planandwarmdo no I/O and read no clock. - sizing
- Right-sizing advice from the job history: the spread of each profile’s and each job’s sampled peaks, waits and
slot use, and the
memoryandslotsto set. Pure: the store reads the history, the daemon serves the result (api::Sizing). It never changes the config: a client applies advice throughPUT /v1/config, which validates it like any other config, and under[sizing] autothe daemon applies whatauto::changespicks the same way. - store
- The job history: a SQLite database of jobs, their runners, steps, samples and logs, the events clients resume
from, cache sizes, the paused repositories and where the notifier got to. Owns the schema and its migrations, the one writer and the event
broadcast. Writes are messages to a writer thread, so the engine never waits on the disk; reads and pruning run
on Tokio’s blocking pool, pruning on its own connection, a batch at a time. It decides nothing about scheduling
and stores no secret: no token, no JIT config, no runner
_diaglog.