Expand description
The commit service’s loop.
What:
The resident service’s loop: accept connections, queue requests in arrival order, land what is queued as a batch,
answer each client, and exit when told to retire.
Why:
One writer lands every commit, so there is no lock to take, hold or wait for: order is the order of the queue, the
cost of the one durable write is shared by the batch, and a client that waits blocks on its socket instead of
polling (doc/planning/cli-git-resident-service.md). The service never starts itself: the operating system hands it
the listening socket (socket activation), or a development run binds one.
In TS you’d write (pseudocode):
for await (const batch of queue.batches()) { const outcomes = await landBatch(batch); for (...) reply(outcome); }Structs§
- Serve
Settings - How a service run behaves apart from where it listens and what it lands.
Enums§
- Bind
- Where the listening socket comes from.
Constants§
- BATCH_
COST_ KNEE - The largest batch whose landing still costs about what its size predicts: 256. Measured with the service binary on throwaway
repositories, 2026-11-03, bursts of simultaneous commit requests (
MAX_BATCHraised to 4096 for the probe, three rounds alternating over 64, 128, 256, 512 and 1024 clients, other sessions running, a debug build): a landing took 71 to 76 ms for 62 to 63 requests, 82 to 85 ms for 126, 104 to 109 ms for 253 to 255, 193 to 204 ms for 509 to 511 (once 2,002 ms, a host stall) and 525 to 547 ms for 1,021 to 1,023. The cost of each added request is 0.16 ms up to 254 requests, 0.36 ms from there to 510, and 0.66 ms to 1,022, so the cost per request has not yet doubled at 256. The time a client waits for a burst of 128 was 176 to 206 ms in one landing and 243 to 249 ms in three at the old cap of 64. - IDLE_
EXIT - How long the service waits with nothing to do before it exits; the manager’s socket stays, so the next connection starts it
again. Bazel’s server does the same with
--max_idle_secs, whose default is three hours, which is this value’s precedent. Measured cost of exceeding it: of 1,051 commits in the commit timing log (2026-11-02T09:01:37Z to 2026-11-03T15:10:12Z), the 10 that followed an idle gap of more than three hours reached the service in at most 70 ms (reachMs) after a start wait of at most 47 ms (startWaitMs); 110 idle exits happened in that window. The 28 running services held 212 MiB together (7.9 MiB each,systemctl --user show --property=MemoryCurrent). A shorter exit would trade at most that start for that memory; the owner’s bound is that a commit should not take 5 s longer than native Git (SPEC.md). Kept at three hours as the coordinator’s pick under the owner’s delegation, open to the owner’s veto (doc/planning/cli-git-shipped-limits-audit.md, “Sizes and ages of the service’s own housekeeping”). - INHERITED_
DESCRIPTOR - File descriptor the service manager passes the listening socket on (
SD_LISTEN_FDS_START). - MAX_
BATCH - The most requests landed as one batch:
BATCH_COST_KNEE. A batch is answered all at once and holds the index lock while it lands, so the cap bounds both. The prototype’s burst reached 64, and production never reached more than one request in a batch (1,302 answered requests, 2026-11-02T09:01:38Z to 2026-11-03T15:11:58Z), so the cap bites only in a burst. Option B of the batch size question, picked by the coordinator under the owner’s delegation, open to the owner’s veto (doc/planning/cli-git-shipped-limits-audit.md, “Picked for these follow-ups”). - REQUEST_
READ_ TIMEOUT - How long a connection may take to send its request line before it is dropped.
Functions§
- bind
- What: Opens the listening socket. Why: Socket activation hands over a bound socket, which is the normal way; the others serve tests and development runs.
- serve
- What: Runs the service until it is told to retire. Why: Recovery runs before the first connection is accepted; then the loop takes everything queued as one batch, groups it by branch in order of first arrival, lands each group, and answers.
- work_
loop - What:
Runs the after-commit work of each repository named, one repository at a time, folding wakes that arrive while it
works into the next round, and looks again at a repository whose claims another instance held when their lease is over.
Why:
Draining claims everything pending, so a burst of wakes for one repository is one pass. The instance that held a claim
may have died, and nothing but this loop would then wake the work: it waits for a wake no longer than the first lease still
running, and the service counts itself busy meanwhile, so it does not exit idle with work claimed by a dead holder. The same
holds for a push the service stopped: the loop owns the plan of its new tries (
PushRetries), each round hands the workers what is due and applies what they ask, and the wake for the earliest plan is kept in the same schedule as the lease wakes, so the service neither forgets the plan nor exits idle while a try is pending.