Help us shape the future of Go! Take the 2026 Go Developer Survey

jobcgroup

package
v0.2.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package jobcgroup owns the per-job parent cgroup: the one cgroup that, on Linux, holds every container of one job.

Layout (cgroup v2, cgroupfs driver — CgroupsPath "/<ns>/<id>"):

/sys/fs/cgroup/ephemerd/<runner-id>                 runner, no job limit
/sys/fs/cgroup/ephemerd-dind-<runner-id>/<cid>      dind siblings
/sys/fs/cgroup/ephemerd-dind-<runner-id>/runner     runner, WITH a job limit

The dind siblings land under the job parent on their own: containerd's default spec sets CgroupsPath to "/<namespace>/<id>", and each job's dind namespace is "ephemerd-dind-<runner-id>". runc creates the parent with MkdirAll and only ever removes the leaf, which is why every finished job used to leave an empty ephemerd-dind-* directory behind (477 on ducks and 541 on sharks, 2026-10-23). Remove and SweepStale clean that up.

With runtime memory_limit_mb set, the runner container is moved under the same parent (Dir(id)/runner) so the job's memory.max covers the runner and its siblings together — one budget per job. It cannot simply nest the siblings under the runner's own cgroup instead: cgroup v2's no-internal-processes rule forbids a cgroup that holds processes from having controller-enabled children.

Index

Constants

View Source
const Prefix = "ephemerd-dind-"

Prefix is the name prefix of every job parent cgroup. It must equal dind.DindNamespacePrefix — the parent IS the cgroup containerd derives from the job's dind namespace — and dind's tests pin that.

View Source
const Root = "/sys/fs/cgroup"

Root is the cgroup v2 mount ephemerd manages job cgroups under.

View Source
const RunnerLeaf = "runner"

RunnerLeaf is the runner container's cgroup name inside the job parent when a job memory limit is configured. Sibling container ids are 64-hex digests, so it cannot collide with one.

Variables

This section is empty.

Functions

func Dir

func Dir(jobID string) string

Dir returns the job parent cgroup's path relative to the cgroupfs root, in the "/<name>" form OCI CgroupsPath takes.

func Ensure

func Ensure(root, jobID string, l Limits) error

Ensure creates the job parent cgroup under root if it is missing and writes its memory budget. Idempotent, and called before every container of the job is created, so a parent that SweepStale removed between two of the job's containers comes back with its limits rather than without them.

func Remove

func Remove(root, jobID string) error

Remove deletes the job parent cgroup once its containers are gone: any leftover empty child first, then the parent. Missing is success. A cgroup that still holds processes is left alone (rmdir refuses it) and reported; SweepStale retries it later.

func RunnerPath

func RunnerPath(jobID string) string

RunnerPath is the runner container's CgroupsPath when the job has a memory budget.

func Sweep

func Sweep(grace time.Duration, live map[string]bool, log *slog.Logger)

Sweep is SweepStale on the real cgroupfs, logged. A sweep failure is never fatal — the leak it cleans up is slow and harmless in the short term.

func SweepStale

func SweepStale(root string, grace time.Duration, now time.Time, live map[string]bool) (int, error)

SweepStale removes job parent cgroups under root that hold no processes and no child cgroups, whose directory has not changed for grace, and whose job is not in live. It never removes one with processes or children, and never one belonging to a job this daemon is still running: without a memory limit a live job's parent is empty between two of its sibling containers, and an rmdir landing inside runc's mkdir-parent/mkdir-leaf window would fail that container's start. live is keyed by job (runner container) id; nil means no job is live.

The grace is measured against the directory's mtime, which cgroupfs bumps when a child cgroup is created or removed (not when processes join or a limit is written). It backstops a job the live set cannot see yet.

Returns how many it removed.

Types

type Limits

type Limits struct {
	MaxBytes  int64 // memory.max
	HighBytes int64 // memory.high; 0 = no soft limit
}

Limits is the job's memory budget in bytes. Zero values mean no limit.

func (Limits) Enabled

func (l Limits) Enabled() bool

Enabled reports whether the job has a memory budget at all. Without one nothing is created and the runner keeps its historical cgroup.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL