Repository navigation
Share one pixi package cache across containers: --mount + PIXI_CACHE_DIR from workspace_up #232
Copy link
Copy link
Closed
Description
Graduated from map blooop/dotfiles#13's pixi-cache fog item after a measured investigation (2026-08-15). Owner: devlaunch alone — dotfiles need no edit, no repo's devcontainer.json is involved.
Measured case
The container profile's real workload is 23 pixi-global envs. pixi global sync with a scratch PIXI_CACHE_DIR/PIXI_HOME:
- COLD (empty cache): 62–113 s, 1.2 GB downloaded
- WARM (fresh PIXI_HOME, pre-warmed cache): 18–28 s
- NO-OP (envs present): 0.6 s
So a shared cache saves ~40–90 s and 1.2 GB of network per cold container, compounding with wayfinder's N-containers-per-map pattern. wayfinder#39 already names dotfiles/tool provisioning the dominant cold-launch cost; this is that cost's biggest slice.
Facts the design leans on (verified)
- The shareable part is exactly
~/.cache/rattler/cache(content-addressedpkgs/, per-package.lockfiles). Envs and trampolines are prefix-baked and must stay per-container. PIXI_CACHE_DIRis honored and wins overRATTLER_CACHE_DIR(pixi 0.76.1, verified viapixi info) — so the dotfilesinstall.sh's conditionalRATTLER_CACHE_DIRfallback is harmlessly overridden; an inherited env var is consumed as-is with no dotfiles change.- Concurrency: safe. Two simultaneous
pixi global syncruns sharing one fresh cache (separate PIXI_HOMEs) → both exit 0, all binaries work. rattler locks per package. The known bug (Error: failed to collect prefix recordsduring concurrent execution on HPC (SLURM + Lustre) prefix-dev/pixi#5476) is a shared env prefix, not a shared cache — it argues for exactly this split. Never share PIXI_HOME/envs across containers. devpod uptakes--mount type=bind,source=…,target=…and--workspace-env/--dotfiles-script-envfirst-class;workspace_up()(dl.py ~3495) already appends--init-env/--dotfiles/--workspace-env-file, so this is two more entries at the one argv seam.- uid: containers write as vscode (uid 1000 = host user here), but that is not guaranteed for other
remoteUsers — hence a dedicated host dir (~/.cache/devlaunch/pixi), never the host's real~/.cache/rattler/cache; this also keeps a hostpixi clean cachefrom yanking packages under a live container, and makes GC trivially safe (rm -rfof a pure cache). - Cross-filesystem hardlink fallback is a copy: measured 20.7 s for 1.2 GB — still far cheaper than downloading.
Done when
workspace_up()appends--mount type=bind,source=$HOME/.cache/devlaunch/pixi,target=/home/vscode/.cache/devlaunch-pixi,--workspace-env PIXI_CACHE_DIR=/home/vscode/.cache/devlaunch-pixi, and the matching--dotfiles-script-env(the dotfiles install script is the consumer).- Spawn-count/argv pins updated at the same seam the existing up-args tests use.
- Live acceptance: two back-to-back
dllaunches of different repos on a clean scratch cache — the second one'spixi global syncfinishes <30 s with no network fetch; twodl upin parallel leave both containers with workingrg/go/jq. - README notes the shared cache dir and that deleting it is always safe.
Recorded alternatives / falsification
- Not chosen: sharing a whole PIXI_HOME volume (~0.6 s installs) — puts concurrent syncs on one prefix tree, which is exactly pixi#5476. Do not.
- Falsification condition: if the base image ever bakes the pixi manifest in, the delta collapses toward the 0.6 s no-op number and this mount stops earning its keep — reopen then.
- GC story for the dedicated dir is deliberately out of scope (it is a pure cache;
rm -rfis the GC).
This ticket was generated by AI during investigation follow-through; measurements above were taken live on 2026-08-15.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
blooop commentedon Aug 15, 2026
breadcrumb: building this ticket. Restating the slice: the one
devpod upargv seam grows three entries — a bind mount of a dedicated host cache dir onto a container-side path,--workspace-env PIXI_CACHE_DIR=<that path>, and the same assignment repeated as--dotfiles-script-envbecause the dotfiles install script is a separate env scope from the workspace. The host source directory is created by dl before devpod is spawned rather than left to whichever runtime is underneath, so ownership lands on the invoking user instead of root.Seams I will test at, all pre-agreed by the ticket:
upinvocation out of everything a launch spawns, patched atrun_devpod. New assertions in the same class idiom as the identity/ide/devcontainer-path pins that already live there.upargv by equality rather than by membership. It is the pin that would otherwise silently absorb three new flags, so it is where red shows first.Host path is derived from the same cache-home resolver the rest of dl's storage already goes through, so it follows
XDG_CACHE_HOMEand no/home/<user>is written down anywhere.blooop commentedon Aug 15, 2026
breadcrumb: PR #236 opens this. The
upargv now carries the bind mount and the samePIXI_CACHE_DIRassignment twice — once for the workspace, once for the dotfiles install script, which is the scope the sync actually runs in.One thing checked rather than assumed, and it changed the shape of the change: the container runtime refuses a bind mount whose source directory does not exist, rather than creating it. So creating the host directory before spawning is not a nicety — without it the first launch on any fresh machine fails outright. It is created through the same cache resolver the rest of dl's storage uses, so it follows a scoped cache home and the purge already knows about it. A directory that cannot be created drops the three flags and lets the launch proceed, which lands the container back on exactly the behaviour it had before this existed.
Live acceptance ran in full on real containers. Second container's sync finished in 16 s having pulled 13 KB, against 667 MB for the first — comfortably inside the ticket's bound. Two parallel launches both succeeded and, syncing simultaneously against one emptied cache, downloaded 666 MB between them rather than each; every tool worked in all four containers afterwards. Deleting the whole cache directory under two live containers left both entirely unharmed, which is the safety claim tested rather than asserted.
Two things a reviewer should weigh, both written up on the PR. The dotfiles install script recursively chowns
$HOME/.cachewhen it finds it root-owned, and the mount target sits inside that — benign at the uid seen here and confined to a pure cache, but a genuine cross-container side effect of the settled target path. And the container profile's applied package manifest currently contains only chezmoi, so a stock launch would have measured nothing; the numbers above come from a seeded manifest at roughly half the scale the ticket measured. The mechanism is proven; the win is latent until that manifest carries the real workload again.blooop commentedon Aug 15, 2026
breadcrumb: PR #236 is open and fully green — every CI matrix leg, e2e, prek and coverage. Build stage ends here; the next move is review in fresh context. The slice: every container dl creates is now put on one shared, dedicated host directory of downloaded pixi packages, with the cache path delivered to both the workspace and the dotfiles install script, and the host directory created before the spawn because the runtime will not create it.
blooop commentedon Aug 15, 2026
Review complete on PR #236: Approve on both axes (Standards, Spec). All three argv entries and the load-bearing mkdir mutation-verified; live acceptance audited (the parallel-fetch arithmetic — 666MB between two containers vs 667MB for one — is the convincing evidence). Four residues fixed during review (f73ff26). Known caveat, recorded on map blooop/dotfiles#13: the stock container manifest is chezmoi-only today, so the win is latent until the manifest carries real packages. #236