Skip to content

perf(docker): kill the cold-start chown bottleneck + warn about first-build time - #82

Merged
nbkdoesntknowcoding merged 1 commit into
mainfrom
fix/cold-start-build
Jul 9, 2026
Merged

nbkdoesntknowcoding merged 1 commit into
mainfrom
fix/cold-start-build

Conversation

@nbkdoesntknowcoding

Copy link
Copy Markdown
Owner

Fixes the two issues from the Mnema cold-start benchmark: the ~7-min chown build bottleneck and the silent-wait UX gap.

The bottleneck

A cold docker compose up -d --build took ~9:43; ~7 min was three recursive chown -R steps rewriting every inode over huge node_modules / Chromium trees (api 169.9s, workers 128.7s Chromium-layer export, web 123.6s).

Root cause: files were COPYed as root then chowned to node in a separate RUN layer. But the runtime never writes under /app (uploads to object storage; web sessions are sealed iron-session cookies, not Astro's filesystem session store), so the whole-tree chown was unnecessary.

Fix

  • api / collab / web: COPY --chown=node:node the app code + build output; delete RUN chown -R node:node /app. Prod node_modules stays root-owned + world-readable (read-only at runtime).
  • workers: delete chown -R node:node /app /ms-playwright — the browsers path is already world-readable/executable via the existing chmod -R a+rX, and Chromium's writable profile lives under HOME=/home/node. Stops rewriting the whole Chromium tree into a second layer.
  • All four images still run as non-root node. Base images, versions, tsc/build config untouched.

Silent-wait UX

scripts/self-host-init.sh now warns the first build takes several minutes and looks idle while images build (not a hang), and points at docker compose logs -f.

Checklist

  • One logical change; matches surrounding style.
  • Signed off for the DCO.
  • Core change — not enterprise-adjacent.

…-build time

Cold `docker compose up -d --build` spent ~7 of ~9.7 min in three recursive
`chown -R` steps that rewrite every inode over huge node_modules / Chromium
trees (api 169.9s, workers 128.7s Chromium-layer export, web 123.6s).

Root cause: files were COPYed as root then chowned to node in a separate RUN
layer. The runtime never actually writes under /app (uploads to object storage,
web sessions are sealed iron-session cookies, not Astro's fs session store), so
the whole-tree chown was unnecessary.

- api / collab / web: COPY --chown=node:node the app code + build output; drop
  `RUN chown -R node:node /app`. Prod node_modules stays root-owned and
  world-readable (read-only at runtime).
- workers: drop `chown -R node:node /app /ms-playwright` - the browsers path is
  already world-readable/executable via the existing `chmod -R a+rX`, and
  Chromium's writable profile lives under HOME=/home/node. Stops rewriting the
  entire Chromium tree into a second image layer.
- All four images still run as the non-root `node` user (unchanged). Base
  images, versions, and tsc/build config untouched.

Also: self-host-init.sh now warns that the first build takes several minutes and
looks idle while images build (not a hang), and points at `docker compose logs -f`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: nbkdoesntknowcoding <nischaybk@theboringpeople.in>
@nbkdoesntknowcoding
nbkdoesntknowcoding merged commit a6f38ad into main Jul 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant