Skip to main content

Module service_work

Module service_work 

Source
Expand description

The service’s consumer of after-commit push and upkeep work. What: The service’s consumer of after-commit work: pending push and maintenance work items of one repository are claimed, coalesced, run, settled, and a push that failed leaves a record that the person’s next wrapper command shows. Why: A commit must not wait for the network or for upkeep, so the wrapper leaves a record and the resident service does the work on its own thread (doc/planning/cli-git-resident-service.md, “After-commit work”). The service is the only pusher of the repositories it serves, so no lock is needed: several pending pushes of one branch become one push, and a service that died mid-push is noticed by the lease of its claims running out, never by a process id: the holder renews the lease while it works, so a successor that starts beside a holder that is still running leaves its claims alone, and one that starts after the holder died takes them back as soon as the lease is over. Other kinds of work (the standards review) are never claimed here.

In TS you’d write (pseudocode):

for (const group of coalesce(await claimAll(workDir, ['push', 'maintenance']))) settle(group, await handler(group));

Structs§

Drained
What: What one drain of a directory hands back: how long until it must be looked at again for a claim another instance holds, and the changes it asks of the retry plan. Why: A drain runs on a worker and cannot change the plan, which the service loop owns; it returns what it did and the loop applies it (PushRetries::apply).
GitHandlers
The handlers that run real Git.

Enums§

Verdict
What a handler came to.

Constants§

CLAIM_LEASE
How long a claim goes without a renewal before another instance runs its item again; the holder renews it three times in this span while it works (service_claim_renewal.rs), so a holder that is slow keeps its claim and one that died loses it after this long. Measured by killing a throwaway service during a claim: the service binary in a fixture repository claimed a push held by the remote’s hook, was killed with SIGKILL 1.5 s after the claim (with its process group), and a new service was started and woken; the push was made again 119.57, 119.56 and 119.55 s after the kill in three runs (2026-11-03), so the cost of a kill is the lease to within half a second. No kill of a commit service appears in the user journal of this host (19 boots), so the kills a person meets were not counted. The renewal thread is independent of the landing (service_claim_renewal.rs), so a landing that stalled for 119.8 s (the longest total_ms in the service journal) does not stop renewals; a stall of the whole process longer than the 80 s a renewal may be late would. Kept at 120 s as the coordinator’s pick under the owner’s delegation, open to the owner’s veto (doc/planning/cli-git-shipped-limits-audit.md, “Picked for these follow-ups”, batch size and claim lease, option B).
MAX_TRIES
How many times an item is tried before it is given up on.
SERVICE_KINDS
The kinds of work the service runs itself.

Traits§

WorkHandlers
What runs each kind of work.

Functions§

drain
What: Runs everything pending for one repository: takes back the claims whose holder stopped renewing them, claims every pending push, maintenance and review item, runs one push per branch and one upkeep per repository, settles the items, and leaves a notice for each failed or skipped push. Gives how long until a claim another instance still holds runs out its lease, or nothing when there is none. Why: Coalescing keeps a burst of commits to one push; a handler that fails leaves the items in failed, not in a loop. A claim found in this directory may belong to a live instance (a restarted service starts beside the one it replaces, and the linked worktrees of a bare repository share a directory), so only its lease says it was abandoned; the caller is told when to look again, because nothing else would wake it once the lease is over. This keeps no retry plan: a push that could pass is reported as failed, as for handlers that do not retry. The service’s rounds use drain_planned instead.
drain_common_records
What: Runs the records the releases before one service per worktree left in the common directory of a bare repository, from the instance of a linked worktree: nothing for a repository with a main worktree, for a main worktree and for a directory with no commondir. Why: Those releases kept every worktree’s records in the common directory. A repository with a main worktree has an instance whose own directory that is, and it runs them (the main worktree’s current records live there too), so a linked instance must not. A repository whose worktrees are all linked has no such instance, and its pushes would sit there with no notice. Several linked instances may drain the directory at once, so a claim is taken back only after its lease, which the holder renews while it works.
drain_common_records_planned
drain_common_records for a service round: first is the pause before the first new try of a push that could pass (nothing keeps no plan), and the plans the drain asks for are keyed by the common directory, which the service loop wakes by itself when one is due; that wake drains the common directory as a directory of its own, which has no commondir.
drain_common_records_with_lease
drain_common_records with the lease given, so a test can use a short one.
drain_planned
drain for a service round: the pushes due again come with the request, and the changes the drain asks of the retry plan are given back with the wait, for the service loop to apply.
drain_planned_with
drain_planned with the lease and the renewal given.
drain_with_lease
drain with the lease given, so a test can use a short one.
drain_with_renewal
drain_with_lease with the way its claims are kept fresh given, so a control can drive the renewal itself.
is_acceptable
What: Whether an item is one this service should act on for this repository. Why: Anyone who can write the work directory can write an item, so the fields that become a directory, a reference or a program argument are checked before they are used.
run_planned_round
What: Runs one round over directories with the retry plan: takes what is due for each directory out of the plan, hands it to that directory’s worker as an owned value, applies the changes the workers ask once they are done, and gives for each directory when to look at it again, whichever is first of its leases and its plan. Why: The plan is owned by the caller and changed here on the caller’s thread only, so the workers share nothing and no lock is taken. A directory whose drain planned a push under another directory (a common directory of a bare repository) is named too, so that its wake is not lost.
run_round
What: Runs one round of wakes: holds each wake’s review credential in memory for the round, drains each named repository once, repositories side by side, and drops the credentials when the round ends. Gives, for each repository that has a claim another instance holds, how long until that claim’s lease runs out, in the order the repositories were named. Why: The credential is held only for the reviews of the round that brought it; a service that restarts before the round runs has none, and its reviews record the plain “no key” outcome. The service looks at such a repository again when the time is over, because the holder may have died and nothing else would wake the work. Repositories share nothing, so the round drains them side by side (service_round.rs); the credentials are passed to the workers as values in a copy of the handlers made for this round, so nothing is shared mutably and no lock is taken.
run_round_on
run_round with the host’s resources chosen by the caller, so a control states a host of any size.
work_directory
The work directory of a repository.

Type Aliases§

Wake
What a wake message brings: the repository to work on and the review credential that came with it, if any.