build: cache native release compilation - #3832
Conversation
amokan
left a comment
There was a problem hiding this comment.
Approved with, what I view to be, non-blocking 🤖 items worth noting
| COPY Cargo.toml Cargo.lock ./ | ||
| COPY native native/ | ||
| RUN set -e; \ | ||
| for crate in arrowipc_ex ch_compression_ex mapper_ex sqlparser_ex; do \ |
There was a problem hiding this comment.
Non-blocking 🤖
the crate list
arrowipc_ex ch_compression_ex mapper_ex sqlparser_exis hardcoded, duplicatingCargo.toml's members. A 5th NIF crate silently drops out of the prebuild with no signal; a renamed/removed crate is worse —cargo rustc --package <gone>exits non-zero andset -ehard-fails the production image build. Options: (a)RUN cargo build --workspace --release --locked— with no trailing rustc args it produces identical units/fingerprints to Rustler's cargo rustc and parallelizes instead of serializing; (b) derive fromcargo metadata --no-deps; (c) guard the list againstCargo.tomlmembers. Recommend (a).
| - uses: docker/build-push-action@v7 | ||
| with: | ||
| file: ./Dockerfile.multi-step | ||
| file: ./Dockerfile |
There was a problem hiding this comment.
Non-blocking 🤖
Switching the PR check from
Dockerfile.multi-stepto./Dockerfileroughly doubles cold-cache cost against an unchangedtimeout-minutes: 30.Dockerfile.multi-stepstartsFROM supabase/logflare:base(apt/nodejs/rustup,mix deps.compile,npm ci,cargo fetchalready baked); the productionDockerfileredoes all of it. And the cache is cold more often than it looks: this workflow triggers only onpull_request/workflow_dispatch, nevermain, socache-to: type=gha,scope=docker-build-checkonly ever writes PR-scoped caches readable by that PR alone. Every PR's first Docker Build Check is a full cold build on a 4-vCPU runner — plausibly 22–26 min against the 30-min cap. Options: (a) addpush: branches: [main]so the shared default-branch cache gets populated; (b) raisetimeout-minutesto 60; (c) use the Blacksmith runner the other Docker jobs use. Recommend (a)+(b).
|
|
||
| # check installed correctly | ||
| RUN cargo version | ||
| COPY . ./ |
There was a problem hiding this comment.
Non-blocking 🤖
COPY . ./re-stampsnative/**mtimes, so the cached native layer won't survive on CI the way it does locally. BuildKit preserves build-context mtimes onCOPY(verified empirically), andactions/checkoutwrites every file with the current time — so on a prebuild-layer cache hit,native/**/*.rslands newer than the/app/targetartifacts restored from that layer, and cargo's mtime freshness check recompiles + relinks all four local crates insidemix release. Registry deps keepPrecalculatedfingerprints so most of the win survives, but the "15.3s release step" was measured locally and won't reproduce in CI. Options: (a) normalize mtimes —find /app/native /app/Cargo.toml /app/Cargo.lock -exec touch -h -d @1 {} +before thecargo rustcstep and again afterCOPY . ./(safe: a genuine native change busts theCOPY native native/layer anyway); (b)RUN --mount=type=cache,target=/app/target(butcache-to: type=ghadoesn't export cache mounts, losing the cross-runner win); (c) accept it and drop the 15.3s claim. Recommend (a).
Rustler invokes cargo rustc for each NIF during mix release. Cargo does not reuse final crate units produced by cargo build for that command mode, so prebuild each workspace package with cargo rustc and document the invariant.
Summary
cargo rustcbefore copying ordinary application sourceDockerfilerather than the alternate multi-step fileMotivation
The production Dockerfile currently compiles all native crates inside
mix releaseafterCOPY . ./. Any Elixir source change therefore discards the native compilation cache.The Docker Build Check previously built
Dockerfile.multi-step, while production builds use the defaultDockerfile. Because this PR changes the native compilation layers in the production Dockerfile, continuing to build the alternate file would not validate the affected production path. The new cache layout retains fast warm builds without relying on the alternate Dockerfile.In main run 31831544506,
mix releasetook 236.6s on arm64, with native compilation occupying roughly the first 216s. The dedicated layer uses the same per-packagecargo rustc --releaseoperation as Rustler so subsequentmix releaseinvocations can reuse the final crate artifacts, not only downloaded dependencies.Validation
LOGFLARE_COMMIT_SHAStack
ci/isolate-docker-build-caches