feat(stability): default-on memory-pressure protection (earlyoom)
Some checks failed
Check / eval (push) Has been cancelled
Some checks failed
Check / eval (push) Has been cancelled
modules/nixos/oom.nix — running out of memory now kills the offending process (with a desktop notification via systembus-notify) instead of freezing the desktop for minutes until the kernel OOM killer fires. earlyoom over systemd-oomd, deliberately: oomd kills whole cgroups, and a Hyprland session runs as ONE scope (nothing here spawns per-app systemd scopes, unlike GNOME) — under pressure oomd would take out the entire desktop to save it. earlyoom kills the single largest process before the thrash point. nixpkgs default-enables oomd in an inert state (no slices monitored); it is disabled outright so there is one owner. Session plumbing is --avoid-listed (unanchored — NixOS wrappers rename comm to .foo-wrapped); no --prefer tuning, largest-RSS selection already finds the hog. All mkDefault; opt out with services.earlyoom.enable = false (README note added). Verified: V0 (flake check) + V2 — new checks.oom-protection runNixOSTest, executed: a chunked allocator (686 MB peak, 1 GB VM) is SIGTERM'd by earlyoom in 0.1 s, a bystander unit survives (the process-level granularity the module exists for), and systemd-oomd is asserted inactive. 25 s runtime. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,7 @@ let
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ./services.nix ./hardware.nix ./timezone.nix ];
|
||||
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ./services.nix ./hardware.nix ./timezone.nix ./oom.nix ];
|
||||
|
||||
config = {
|
||||
# Distro branding. distroName flows into /etc/os-release PRETTY_NAME,
|
||||
|
||||
42
modules/nixos/oom.nix
Normal file
42
modules/nixos/oom.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
# Memory-pressure protection: keep the desktop alive when RAM runs out.
|
||||
#
|
||||
# A workstation that compiles from source WILL exhaust memory eventually —
|
||||
# a big `nix build`, a runaway eval, a browser tab. The kernel's own OOM
|
||||
# killer acts only after the system has thrashed itself unresponsive
|
||||
# (often minutes of frozen desktop) and then picks by badness score,
|
||||
# which can land on the compositor.
|
||||
#
|
||||
# earlyoom over systemd-oomd — a deliberate choice: oomd kills whole
|
||||
# cgroups, and a Hyprland session runs as ONE scope (nothing spawns
|
||||
# per-app systemd scopes here, unlike GNOME), so under pressure oomd
|
||||
# would take out the entire desktop to save it. earlyoom kills a single
|
||||
# process (highest oom_score ≈ the hog) BEFORE the thrash point — "kill
|
||||
# the build step, keep the session". nixpkgs default-enables oomd in an
|
||||
# inert state (no slices monitored); it's disabled outright below so
|
||||
# there is exactly one owner of the OOM story.
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
services.earlyoom = {
|
||||
enable = lib.mkDefault true;
|
||||
|
||||
# Desktop toast when something is killed (relayed via
|
||||
# systembus-notify), so a vanished build/tab is explained rather
|
||||
# than mysterious.
|
||||
enableNotifications = lib.mkDefault true;
|
||||
|
||||
# Never pick the session plumbing: losing the compositor or the lock
|
||||
# screen IS the outage this module exists to prevent (and killing a
|
||||
# Wayland session-lock client trips its go-to-a-tty failsafe). No
|
||||
# --prefer tuning: highest-memory selection already targets the hog.
|
||||
# Matched unanchored — NixOS wrappers rename comm to ".foo-wrapped".
|
||||
extraArgs = lib.mkDefault [
|
||||
"--avoid"
|
||||
"(Hyprland|hyprlock|greetd|waybar|pipewire|wireplumber|Xwayland|nix-daemon|systemd)"
|
||||
];
|
||||
};
|
||||
|
||||
# One owner (see header): oomd ships default-on but inert; make the
|
||||
# earlyoom choice explicit and total.
|
||||
systemd.oomd.enable = lib.mkDefault false;
|
||||
}
|
||||
Reference in New Issue
Block a user