perf(pre-commit): run prettier in its own systemd-run scope

Wrap pre-push prettier --check in a 1 GiB systemd-run scope so its Node
heap is independent of the outer 4 GiB pre-push cgroup, which has
already accumulated page-cache footprint from pytest/mypy/pylint/bandit
by the time prettier runs. Falls back to direct invocation when
systemd-run is unavailable.
This commit is contained in:
Krzysztof kuhy Rudnicki 2026-05-14 21:12:32 +02:00
parent 7ddab620bc
commit dffbdac091
3 changed files with 60 additions and 4 deletions

View File

@ -0,0 +1,27 @@
{
"intent": "Isolate the pre-push prettier check in its own systemd-run scope so prettier's Node memory budget is independent of the outer 4 GB pre-push cgroup's accumulated page cache from pytest/mypy/pylint/bandit. Eliminates the SIGTERM that aborted force-pushes despite a tightened file scope.",
"scope": [
"scripts/run_prettier_capped.sh (new wrapper)",
"meta/.pre-commit-config.yaml prettier hook (mirrors-prettier -> local language: system)",
"Non-goal: changing prettier's check semantics or coverage on first-party files"
],
"changes": [
"Added scripts/run_prettier_capped.sh that wraps `prettier --check` in `systemd-run --user --scope --collect -p MemoryMax=1G -p MemorySwapMax=0` with NODE_OPTIONS=--max-old-space-size=768, falling back to a direct invocation if systemd-run is unavailable.",
"Replaced the mirrors-prettier repo hook with a `repo: local` hook calling the wrapper; same types_or/exclude as before so coverage is unchanged."
],
"verification": [
{
"command": "scripts/run_prettier_capped.sh README.md",
"result": "pass",
"evidence": "`Checking formatting...\\nAll matched files use Prettier code style!` exit=0 from inside a fresh systemd-run scope."
}
],
"risks": [
"Requires prettier on PATH (currently provided by the user's global nvm install); CI must install prettier separately or fall back path executes.",
"If systemd-run is unavailable on a contributor's machine, the wrapper still runs prettier directly without the memory cap."
],
"rollback": [
"git revert <this-commit> restores the mirrors-prettier repo hook.",
"Delete scripts/run_prettier_capped.sh if no longer referenced."
]
}

View File

@ -326,13 +326,16 @@ repos:
# ===========================================================================
# CHECK JSON/YAML/TOML formatting (runs on push only — slow Node.js startup)
# ===========================================================================
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8
- repo: local
hooks:
- id: prettier
name: prettier (capped scope)
# Wrapper runs prettier inside its own systemd-run scope so its
# memory budget is independent of the outer pre-push cgroup that
# has already accumulated page cache from pytest/mypy/pylint.
entry: scripts/run_prettier_capped.sh
language: system
types_or: [yaml, json, markdown]
# Skip vendored/mirrored content and large generated reports so the
# pre-push Node heap stays well under the cgroup memory cap.
exclude: >-
(?x)^(
Bash/.*|

26
scripts/run_prettier_capped.sh Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Run prettier --check inside its own systemd-run scope so its memory
# budget is independent of the outer pre-push cgroup (which has already
# accumulated page-cache footprint from pytest/mypy/pylint/bandit).
#
# Falls back to a direct invocation when systemd-run is unavailable
# (CI / containers without systemd user instance).
set -euo pipefail
if [ $# -eq 0 ]; then
exit 0
fi
# Cap Node heap on top of the cgroup limit for belt-and-braces safety.
export NODE_OPTIONS="${NODE_OPTIONS:-} --max-old-space-size=768"
if command -v systemd-run >/dev/null 2>&1 \
&& systemctl --user is-active --quiet default.target 2>/dev/null \
|| command -v systemd-run >/dev/null 2>&1; then
exec systemd-run --user --scope --quiet --collect \
-p MemoryMax=1G \
-p MemorySwapMax=0 \
-- prettier --check "$@"
fi
exec prettier --check "$@"