Skip to content

Commit 44ba5fa

Browse files
brainrakeclaude
andcommitted
feat(nix): add site-nix-gc to the site profile
Refs: MPG-1384 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent d493f67 commit 44ba5fa

3 files changed

Lines changed: 71 additions & 19 deletions

File tree

‎nix/docs/site-profile.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Site profile
22

3-
The `site-env-15`, `site-env-17`, and `site-env-orioledb-17` package sets are deployed to `/nix/var/nix/profiles/site`. They hold supautils, and `activate`.
3+
The `site-env-15`, `site-env-17`, and `site-env-orioledb-17` package sets are deployed to `/nix/var/nix/profiles/site`. They hold supautils, `activate`, and `site-nix-gc`.
44

55
`dynamic_library_path` in `postgresql.conf` includes `/nix/var/nix/profiles/site/lib/postgresql` first, then `$libdir`. supautils also remains in `$libdir`, pending cleanup.
66

@@ -19,6 +19,8 @@ nix-env --profile /nix/var/nix/profiles/site --set <store path>
1919

2020
`activate` runs after the switch. It sets up supautils, and gatekeeper where present, idempotently. If it fails, the new generation stays active. Run `activate` again, or roll back.
2121

22+
`site-nix-gc` keeps the current generation and one older one for the site, postgres, and default profiles. It then runs `nix-store --gc` to completion. With systemd it runs in a throttled transient unit. Without systemd it runs under `nice` and `ionice`.
23+
2224
## Roll back
2325

2426
```sh
@@ -28,7 +30,7 @@ nix-env --profile /nix/var/nix/profiles/site --rollback
2830

2931
Rollback switches to the previous generation. `activate` then runs from that generation and makes the machine match it. There is no separate rollback script.
3032

31-
To go further back than the previous generation, install an older version by path.
33+
`site-nix-gc` keeps the current generation and one older one. To go further back, install an older version by path.
3234

3335
New sessions load supautils from the rolled-back profile. Open sessions keep the copy they loaded until they reconnect. Postgres does not restart. A restart applies the change to every session at once.
3436

‎nix/packages/site-env.nix‎

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,75 @@
99
...
1010
}:
1111
let
12+
# Scripts run on the host bash to keep Nix's bash and glibc out of the closure.
13+
writeHostBash =
14+
name: text:
15+
pkgs.writeTextFile {
16+
inherit name;
17+
executable = true;
18+
destination = "/bin/${name}";
19+
text = ''
20+
#!/usr/bin/env bash
21+
set -euo pipefail
22+
${text}
23+
'';
24+
checkPhase = ''
25+
${pkgs.shellcheck}/bin/shellcheck "$target"
26+
'';
27+
};
28+
29+
# Prunes old generations, then runs nix-store --gc. Throttled by a transient systemd unit, or by nice and ionice without systemd.
30+
site-nix-gc = writeHostBash "site-nix-gc" ''
31+
prune() { nix-env --profile "$1" --delete-generations +2; }
32+
prune /nix/var/nix/profiles/site
33+
prune /nix/var/nix/profiles/default
34+
if [[ -L /var/lib/postgresql/.nix-profile ]]; then
35+
prune "$(readlink /var/lib/postgresql/.nix-profile)"
36+
fi
37+
38+
export NIX_REMOTE=local
39+
gc=("$(command -v nix-store)" --gc --quiet)
40+
41+
if [[ -d /run/systemd/system ]]; then
42+
if systemctl is-active --quiet site-nix-gc; then
43+
echo "Garbage collection already running."
44+
exit 0
45+
fi
46+
systemd-run \
47+
--unit=site-nix-gc --collect --no-block --setenv=NIX_REMOTE=local \
48+
-p Nice=19 -p CPUSchedulingPolicy=idle -p CPUQuota=20% \
49+
-p IOSchedulingClass=idle -p IOWeight=1 -p IOWriteBandwidthMax="/nix 20M" \
50+
-p MemoryHigh=10% -p MemoryMax=15% -p OOMScoreAdjust=1000 \
51+
-p RuntimeMaxSec=2h \
52+
"''${gc[@]}" && exit 0
53+
echo "systemd-run failed. Running in the foreground."
54+
fi
55+
56+
throttle=(nice -n 19)
57+
command -v ionice >/dev/null && throttle+=(ionice -c 3)
58+
exec "''${throttle[@]}" "''${gc[@]}"
59+
'';
60+
1261
makeSiteEnv =
1362
version: extraPaths:
1463
let
1564
supautils = self'.legacyPackages."psql_${version}".exts.supautils;
1665
# Site profile activation script. MUST STAY IDEMPOTENT!
17-
activate = pkgs.writeTextFile {
18-
name = "activate";
19-
executable = true;
20-
destination = "/bin/activate";
21-
# Runs on the host bash to keep Nix's bash and glibc out of the closure.
22-
text = ''
23-
#!/usr/bin/env bash
24-
set -euo pipefail
25-
echo "Activating site profile."
26-
echo "supautils at /nix/var/nix/profiles/site/lib/postgresql/supautils.so: picked up next session via session_preload_libraries, if dynamic_library_path includes /nix/var/nix/profiles/site/lib/postgresql."
27-
echo "Site profile activated."
28-
'';
29-
checkPhase = ''
30-
${pkgs.shellcheck}/bin/shellcheck "$target"
31-
'';
32-
};
66+
activate = writeHostBash "activate" ''
67+
echo "Activating site profile."
68+
echo "supautils at /nix/var/nix/profiles/site/lib/postgresql/supautils.so: picked up next session via session_preload_libraries, if dynamic_library_path includes /nix/var/nix/profiles/site/lib/postgresql."
69+
echo "Site profile activated."
70+
'';
3371
in
3472
pkgs.buildEnv {
3573
name = "site-env-${version}";
3674
paths = [
3775
supautils
3876
activate
77+
site-nix-gc
3978
]
4079
++ extraPaths;
41-
passthru = { inherit activate; };
80+
passthru = { inherit activate site-nix-gc; };
4281
};
4382

4483
siteEnvs = {

‎nix/tests/site.nix‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ pkgs.testers.runNixOSTest {
4545
machine.succeed("su postgres -c '${psql_17}/bin/psql -h /tmp -d postgres -c \"select 1\"'")
4646
machine.succeed("su postgres -c '${psql_17}/bin/pg_ctl -D /tmp/pgdata stop'")
4747
48+
# site-nix-gc runs to the end and reports what it freed
49+
machine.succeed("nix-store --gc")
50+
machine.succeed("echo garbage > /tmp/garbage && nix-store --add /tmp/garbage")
51+
machine.succeed("nix-env --profile /nix/var/nix/profiles/default --set $(dirname $(dirname $(readlink -f $(command -v nix-env))))")
4852
machine.succeed("${site-env-17}/bin/activate")
53+
machine.succeed("${site-env-17}/bin/site-nix-gc")
54+
machine.wait_until_fails("systemctl is-active site-nix-gc", timeout=1800)
55+
print(machine.succeed("journalctl -u site-nix-gc --no-pager | grep freed"))
56+
57+
# without systemd the gc runs in the foreground
58+
machine.succeed("mount -t tmpfs none /run/systemd")
59+
machine.succeed("${site-env-17}/bin/site-nix-gc 2>&1 | grep freed")
4960
'';
5061
}

0 commit comments

Comments
 (0)