janitor
janitor
¶
Reconcile stray supervisor process trees against live containers.
The per-container supervisor is meant to die with its container — the
poststop hook group-kills the tree, the supervisor self-terminates
when its container's init PID dies, and PR_SET_PDEATHSIG takes the
service children down with it. Those are the prevention layers. This
module is the reconciliation backstop: a periodic sweep that finds
supervisor trees whose container is no longer running and kills them, no
matter how they were stranded (a poststop that never fired, a host
crash that left the tree, or a supervisor built before the prevention
layers existed).
Unlike the OCI hook — which crun hands the container's environment, so its
nested podman calls are unreliable — the janitor runs from an ordinary
host CLI context (doctor, a task launch), where podman ps answers
normally. That is what lets it use container liveness as the ground truth
the hook cannot.
A tree is identified structurally: the wrapper is a session leader (the
OCI hook spawns it with start_new_session=True), and every descendant
— supervisor, service children — inherits that process group, so one
killpg per group takes the whole tree down. Groups are matched by the
container id carried in each process's argv, and each member's identity
(PID + start time) is revalidated immediately before signalling so a PGID
recycled between the scan and the kill is never touched.
__all__ = ['make_orphan_supervisor_check', 'reap_orphaned_supervisors']
module-attribute
¶
reap_orphaned_supervisors(*, min_age_s=_ORPHAN_GRACE_S)
¶
Kill every supervisor tree whose container is no longer running.
Returns one (container_id, error_or_None) row per tree reaped
(None error when it went down cleanly), or an empty list when
nothing was stray — the steady state. Returns None when podman
was unreachable: liveness is then unknown, so the sweep does nothing and
the caller must not read that as "all clean" (distinct from the empty
list, which means podman answered and found no strays).
A tree is reaped only when its container is absent from the live set, its age is known and past min_age_s, and — at signal time — an original member still occupies the PGID.
Source code in src/terok_sandbox/supervisor/janitor.py
make_orphan_supervisor_check()
¶
A host-side doctor check that reaps supervisor trees without a live container.
Host-level like the stray-sidecar sweep — one reconciliation per
install, not per task — so top-level callers append it rather than
it living in the per-container check list. Podman being unreachable
is surfaced as a warn (the sweep could not run), never a silent ok.