subagent daemon: scope an OOM kill to the session that lost the draw

systemd's default OOMPolicy=stop tears the whole unit down the moment the
kernel kills any process in its cgroup, so a single over-large subagent
takes the daemon and every sibling session with it — measured on a live
agent, both units show OOMPolicy=stop today, which is exactly the "every
live subagent session was cut mid-turn" symptom.

That blast radius is also what would make the preceding commit a bad
trade: deliberately putting this unit first in the OOM queue is only an
improvement if losing one subagent isn't losing all of them. OOMPolicy=
continue scopes the loss to the process the kernel actually chose, and
leaves the daemon alive to report the kill instead of vanishing and being
restarted with an empty session map.

Refs #4316
This commit is contained in:
atlas 2026-09-13 13:05:17 +02:00
commit 33aa2bdbc8
2 changed files with 18 additions and 0 deletions

View file

@ -375,6 +375,14 @@ in
# inherits the value from the daemon, so the ordering covers the
# whole subtree and not just this process.
OOMScoreAdjust = 500;
# systemd's default is `stop`, which tears the whole unit down as
# soon as the kernel kills *any* process in its cgroup — so one
# over-large subagent takes the daemon and every sibling session
# with it, which is the blast radius that makes an OOM here
# expensive. `continue` scopes the loss to the process the kernel
# actually chose and leaves the daemon serving, which is also what
# lets it report the kill rather than vanish and be restarted.
OOMPolicy = "continue";
User = userName;
Group = userName;
}

View file

@ -1402,6 +1402,16 @@ let
in
sub > 0 && own < 0 && sub > own;
}
{
# The pair the case above only makes sense with: preferring this unit
# as the victim is an improvement only if losing one subagent isn't
# losing all of them. systemd's default `stop` would take the daemon
# and every sibling session down with whichever process the kernel
# chose, which is the blast radius that made the preference a bad
# trade in the first place.
name = "one subagent losing the OOM draw does not stop the daemon";
ok = (agentSubagentDaemon agentUncapped).serviceConfig.OOMPolicy == "continue";
}
{
# The doctrine three glue files state, as a property a rewrite has to
# keep: a client is defined by holding a certificate the store accepts,