Skip to content

fix(docker): worker build broke — go mod tidy pruned all deps pre-source#655

Merged
benben merged 1 commit into
mainfrom
ben/fix-worker-dockerfile-tidy-prune
Jun 2, 2026
Merged

fix(docker): worker build broke — go mod tidy pruned all deps pre-source#655
benben merged 1 commit into
mainfrom
ben/fix-worker-dockerfile-tidy-prune

Conversation

@benben
Copy link
Copy Markdown
Member

@benben benben commented Jun 2, 2026

Main is currently red for the worker image — all four
container-image-worker-cd matrix builds fail on c4db37d (the #654
merge). Forward-fix.

Cause

#654 moved the per-DuckDB-version pin into a module-files-only stage
(COPY go.mod go.sum; go get; go mod tidy) ahead of COPY . ..
With no .go files present, go mod tidy sees zero imports and
prunes every require directive, emptying go.mod. The stashed
go.mod.pinned was empty too, so restoring it after COPY . . gave the
final build a depless go.mod:

duckdbservice/appender_init.go:7:2: no required module provides
  package github.com/duckdb/duckdb-go/v2

Main + control-plane images were unaffected — they never run tidy.

Fix

  • Pin with go get pkg@ver (records the require regardless of imports)
    but do not tidy in the source-less stage.
  • Drop the go.mod.pinned stash/restore.
  • Re-run the pin + go mod tidy after COPY . ., once the real
    import set is visible, so tidy keeps every needed require.

Prewarm + module caches from the pre-COPY layers stay valid (same
versions → go get is a fast metadata no-op, prewarmed objects reused).

Verified locally

go mod tidy  (only go.mod/go.sum)         -> duckdb-go requires: 0  (the break)
go get duckdb-go/v2@v2.10502.0 (no tidy)  -> duckdb-go requires: 1, pinned (OK)

Default-path worker binary builds clean.

🤖 Generated with Claude Code

The prewarm restructure in #654 moved the per-DuckDB-version pin into a
module-files-only stage (COPY go.mod go.sum; go get; go mod tidy) ahead
of COPY . .. With no .go files present, `go mod tidy` sees zero imports
and prunes EVERY require directive, emptying go.mod. The stashed
go.mod.pinned was therefore empty too, and restoring it after COPY . .
gave the final build a go.mod with no dependencies:

  duckdbservice/appender_init.go:7:2: no required module provides
    package github.com/duckdb/duckdb-go/v2

All four worker matrix builds failed on main (container-image-worker-cd).
Main + control-plane images were unaffected — they never run tidy.

Fix: pin with `go get pkg@ver` (which records the require regardless of
imports) but do NOT tidy in the source-less stage; drop the
stash/restore. Re-run the pin + `go mod tidy` AFTER COPY . ., once the
real import set is visible, so tidy keeps every needed require. The
prewarm + module caches from the pre-COPY layers stay valid (same
versions → go get is a fast metadata no-op).

Verified locally: `go mod tidy` with only go.mod/go.sum prunes
duckdb-go to zero requires; `go get duckdb-go/v2@v2.10502.0` without
tidy keeps and pins it. Default-path worker binary builds clean.
@benben benben enabled auto-merge (squash) June 2, 2026 10:41
@benben benben merged commit 21ef40c into main Jun 2, 2026
17 checks passed
@benben benben deleted the ben/fix-worker-dockerfile-tidy-prune branch June 2, 2026 10:42
benben added a commit that referenced this pull request Jun 2, 2026
The prewarm added in #654 was premised on a multi-minute CGO compile of
duckdb-go. That premise was wrong: duckdb-go-bindings ships PREBUILT
static libs (libduckdb_*.a etc, ~1.7GB in the module cache) — there is
no DuckDB C++ compile to cache. The other prewarmed dep, pg_query_go,
cold-compiles in ~4s. So the prewarm layer saved single-digit seconds
while adding a confusing extra build step.

Measured on warm main builds after #654:
  main         288s -> 264s
  controlplane 241s -> 229s
The ~10% saving came from the LAYER REORDERING (module + extension
downloads moved ahead of COPY . ., so they cache on source-only PRs),
not from the prewarm. The dominant remaining cost is the final CGO
*link* of the prebuilt static libs (~68s), which caching can't touch
because it changes with every first-party source edit.

Remove the prewarm RUN from all three Dockerfiles. Keep the valuable
reordering and the worker pin-without-tidy fix from #655.

Net build-time wins still live here:
  - module download + extension fetch cached before COPY . .
Real PR-latency lever (separate change): build only linux/arm64 in PR
CI (mw-dev is arm64), halving the worker matrix.
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