fix(build): stop the builder container when the build exits

An idle builder keeps the Docker Desktop VM ballooned: each per-worktree
compose project carries its own ${KICAD_DOCKER_MEM:-32G} cap, build.sh left
the container running afterwards ("interactive use"), and two forgotten
builders plus the VM's page-cache/high-water behavior read as ~56 GB of host
RAM during a ~20 GB build.

stop_builder() now runs from the EXIT trap on every path (success, failure,
Ctrl-C — both the sequential and the pipeline-mode trap). The container is
pure scaffolding — all caches live in the named volumes and `up -d` restarts
it in seconds — so stopping costs nothing. KICAD_KEEP_CONTAINER=1 restores
the old keep-running behavior for interactive debugging; docker/shell.sh is
unaffected (it does its own `up -d`).

Verified live: the full `all --build-deps` run on main left zero containers
running at exit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Viktor Vaczi 2026-07-03 14:42:38 +02:00
commit 1a24c2894e
2 changed files with 20 additions and 3 deletions

View file

@ -57,9 +57,23 @@ export EMSCRIPTEN_VERSION
set -e
# Stop the builder container when the build ends (any exit path). A lingering
# idle builder keeps the Docker Desktop VM ballooned — each project's builder
# is capped at ${KICAD_DOCKER_MEM:-32G}, and with per-worktree compose projects
# two forgotten containers once read as ~56 GB of host RAM (page cache +
# high-water ballooning). The container is pure scaffolding: all caches live in
# the named volumes and `up -d` restarts it in seconds. Set
# KICAD_KEEP_CONTAINER=1 to keep it running for interactive exec/debugging.
_COMPOSE_FILE="$(cd "$(dirname "$0")" && pwd)/docker-compose.yml"
stop_builder() {
if [[ "${KICAD_KEEP_CONTAINER:-0}" != "1" ]]; then
docker compose -f "${_COMPOSE_FILE}" stop >/dev/null 2>&1 || true
fi
}
# Emit a completion/failure marker no matter how the build ends, so the monitor
# can stop on a clean "done" or show an aborted state instead of hanging.
trap '_rc=$?; if [ $_rc -eq 0 ]; then kw_done; else kw_fail $_rc; fi' EXIT
trap '_rc=$?; if [ $_rc -eq 0 ]; then kw_done; else kw_fail $_rc; fi; stop_builder' EXIT
# On Ctrl-C, mark the build aborted so the final dashboard frame shows failed
# (not a stale "running" state). The EXIT trap above also fires; the monitor reads
# the last marker, so the duplicate is harmless.
@ -351,7 +365,7 @@ TOTAL_APPS="${#APPS[@]}"
# Shared pipeline trap: on a failure, kill orphaned background wasm-opt jobs
# (each ~30 GB) and keep the monitor's done/fail marker from the EXIT trap.
_install_pipeline_trap() {
trap '_rc=$?; for p in "${PIPELINE_PIDS[@]}"; do kill "$p" 2>/dev/null || true; done; if [ $_rc -eq 0 ]; then kw_done; else kw_fail $_rc; fi' EXIT
trap '_rc=$?; for p in "${PIPELINE_PIDS[@]}"; do kill "$p" 2>/dev/null || true; done; if [ $_rc -eq 0 ]; then kw_done; else kw_fail $_rc; fi; stop_builder' EXIT
}
if [[ "$PHASE" == "compile" ]]; then