Deliver build-host images by chunks, and resume after a drop - #1804
Open
chrisdok43 wants to merge 1 commit into
Open
Deliver build-host images by chunks, and resume after a drop#1804chrisdok43 wants to merge 1 commit into
chrisdok43 wants to merge 1 commit into
Conversation
The build host now exports the image once as an OCI layout and delivers it to each device the way `wendy run` does from a laptop: QueryLayers and QueryChunks to learn what the device already holds, WriteChunks for only the missing bytes, and PrepareImage to register the image under the localhost:<port>/<repo> name the CLI already creates the container from, so the CLI is unchanged. A transport drop mid-transfer re-dials and resumes from the chunks the device staged instead of restarting the whole image; a fleet deploy costs one build instead of one buildctl pass per device. Agents that predate QueryChunks or PrepareImage keep the registry push as a fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
AI Security ReviewNote Automated security review from Claude. Apply, adapt, silence with Input coverage: 9/9 changed files; 100,688/100,688 bytes reviewed; diff SHA-256 No security findings. |
Contributor
|
@EBro912 When you pick this up, there's an earlier, more detailed, issue WDY-2564 that specs some more thorough requirements. It would be worth cross-checking to see if any of the ideas there should be worked into this PR too and then we can close off both. Edit: Re-add me for review when you're ready! |
thombles
removed their request for review
August 31, 2026 08:10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes WDY-2605.
The gap
The build host built the image fine and then delivered it with a plain registry push: every layer whole, and one dropped connection lost the whole transfer. On Spark 3 (US) → ccr1 (Canada) that was four consecutive deploys dying at "exporting + pushing layers" with
EOFat 56–162s, each retry starting from zero. #1771 retries the connection and says how far the push got, but as its own description says, a half-sent layer can't be replayed through a proxy — this is the fix it deferred.Meanwhile
wendy runfrom a laptop has chunk-diffed into the device's content store for months. Only this leg skipped it.What changes
The build host does what the CLI does, from where it stands:
QueryLayersto skip layers it already holds,QueryChunks/WriteChunksfor only the missing bytes,PrepareImageto register the image underlocalhost:<port>/<repo>— the name the CLI'sCreateContaineralready uses. The CLI is unchanged and cannot tell how the image arrived.WriteChunksstages chunks as they land, so a transport drop re-dials and the nextQueryChunksreports only what's still missing. Four attempts with backoff; cancellation and device refusals are not retried.UnimplementedtoQueryChunksorPrepareImage(pre 2026-08-12) gets the registry push it always did. Taken for that error only — a genuine failure is reported as one, not retried more slowly and blamed on the wrong leg.No proto change.
BuildImageResult.image_digest(always empty before) now carries the manifest digest. The single-target error contractclassifyRemoteBuildErrorkeys on is preserved.Design:
specs/2026-08-26-build-host-chunk-delivery-design.md.Relationship to #1771
Both touch
build_service.go; expect a conflict on whichever lands second. #1771's connection retry and byte accounting still apply to the registry-push path, which this PR keeps as the fallback for old agents.Test plan
go test ./internal/agent/services -race— full suite green, 20 new tests: a fake target agent over bufconn (only missing chunks sent; present layers never chunked; image registered under the right name with config intact); resume after anUnavailablemid-stream with every chunk reaching the device exactly once; fallback routing onUnimplemented; a device refusal neither retried nor fallen back;BuildImageend to end with the test binary standing in for buildctl (one pass for two devices; second pass for an old agent; scratch files removed; error contract).go build ./...,gofmt -s,go vetclean.Hardware verification (2026-08-26)
Agent side-loaded on Spark 3 (build host, US); ccr1 (Orin Nano, Canada) on release
2026.08.25-111847; all traffic via the cloud relay.python-hello: 25.8s end to end. ccr1's agent journal shows the build host diallinglocalhost:50052, sixWrote layer to content store,Assembled image localhost:5000/…, andPrepared image before container start— the chunk path, not the registry. Spark 3 ran exactly one buildctl pass (--output type=oci,dest=…). No fallback.Canceled.100% 150.7MB/150.7MB (28.7s), 34s total — only the missing 48% was sent; the layer was written once, the image assembled, the container started, and staging drained to 0.Not exercised on hardware: the in-run auto-resume after a transport drop (unit-tested). The interruption here was a client cancel, which exercises the cross-run resume case.
🤖 Generated with Claude Code