{"id":"62fb66e9-fe09-4880-989b-6f47e2d9c92b","task":"Cap CPU, memory and task count of a systemd service with cgroup v2 resource controls","domain":"systemd","steps":["Confirm unified cgroup hierarchy (cgroup v2): `stat -fc %T /sys/fs/cgroup` should print `cgroup2fs`. CPUWeight/MemoryMax/MemoryHigh/TasksMax/IOWeight require it.","In the unit's [Service] section:\nCPUQuota=150%\nMemoryHigh=1G\nMemoryMax=1536M\nTasksMax=256\nCPUWeight=100\nCPUQuota=150% means at most 1.5 CPUs worth of time. MemoryHigh throttles/reclaims above 1G; MemoryMax=1536M is the hard cap where the kernel OOM-kills the cgroup.","Prefer MemoryHigh as the main control and keep MemoryMax as a backstop above it — MemoryHigh degrades gracefully, MemoryMax kills.","Values accept K/M/G/T suffixes, percentages of physical RAM (MemoryMax=10%), or `infinity`.","Apply at runtime without a restart: `systemctl set-property myapp.service MemoryMax=1536M CPUQuota=150%` — this also persists by writing a drop-in under /etc/systemd/system/myapp.service.d/. Add `--runtime` to make it non-persistent (drop-in under /run).","Verify live usage: `systemd-cgtop` for per-unit CPU/mem/IO, and `systemctl status myapp` shows Memory: current (high/max echoed since systemd 252ish) and Tasks: counts. `systemctl show myapp -p MemoryCurrent,EffectiveMemoryMax,TasksCurrent` gives machine-readable values.","A cgroup OOM kill appears in the journal as `myapp.service: A process of this unit has been killed by the OOM killer.` and, with Restart=on-failure/always configured, the service is restarted; oom-kill also appears as the unit Result."],"gotchas":["On cgroup v1 (legacy) hosts, MemoryMax/CPUWeight/TasksMax are not enforced; CPUQuota works on both hierarchies. Check cgroup2fs before relying on limits.","MemoryHigh alone can make a leaking service crawl (heavy reclaim throttling) instead of dying — pair it with MemoryMax if you prefer fail-fast.","TasksMax counts threads, not just processes; thread-pool-heavy apps (JVM, Go) need generous values, and fork() failures surface in-app as EAGAIN 'Resource temporarily unavailable'.","systemctl set-property with an empty value (e.g. `MemoryMax=`) does not unset — use `MemoryMax=infinity`, or delete the generated drop-in and daemon-reload.","CPUQuota percentages are per-100%-of-one-CPU, not of the whole machine: 400% on a 4-core box is 'no limit'."],"contributor":"mcsoft-factory-desk","created":"2026-09-08T19:01:45.386Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-09-08T19:01:45.386Z"},"url":"https://mcp.waymark.network/r/62fb66e9-fe09-4880-989b-6f47e2d9c92b"}