Repository navigation
fix(computers): a compose's pulls of its base take turns, and the killed-run test pulls nothing - #688
Open
earakely-scale wants to merge 5 commits into
Open
earakely-scale wants to merge 5 commits into
earakely-scale wants to merge 5 commits into
Conversation
…er holds, not one pulled from ECR Public test_a_run_killed_outright_leaves_its_sandboxes_under_its_root_for_a_supervisor_to_terminate deployed its container sandbox from public.ecr.aws/nginx/nginx:stable-alpine, which the local sandbox pulled anonymously at test time, and failed with "toomanyrequests: Rate exceeded" whenever ECR Public rate-limited the runner (integration-local, runs 43313173134, 43369378729, 43472071259, 43538837017). It now deploys the registry image the integration tests' throwaway registries run (REGISTRY_IMAGE), which the workflow pulls before the tests, under its digest-pinned RepoDigest: a local sandbox doesn't pull an image its Docker holds under a name pinned to a digest, so the container starts with no registry at all. A machine that doesn't hold the image pulls it once from mirror.gcr.io. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s platform check can't break the other's resolve
A compose builds its pairs at once. On this machine's Docker, container/amd64's resolve creates a container of the
base (docker create, which pulls it when Docker lacks it) while container/arm64's platform check runs a container of the
same base for linux/arm64 (docker run, which pulls too), and neither held the image-pull lock a deploy's pull holds.
On Docker's containerd image store the two pulls raced: the amd64 one failed ("could not fetch content descriptor ...
from remote: not found") and left the store holding the amd64 manifest without all its layers, so the next compose of
the env on the runner failed at once with "failed to get reader from content store: content digest ...: not found"
(integration-local-slow 5/12, run 43505816495, browser_gateway_test and clock_desktop_test's chromium compose).
The resolver's docker create and the platform check's docker run now hold the image's pull lock (host_images.pull_lock,
the one host_images.pull holds), so pulls of one image take turns across a compose's threads and across processes; the
integration tier already shares image-pull: locks between its workers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
earakely-scale
marked this pull request as ready for review
November 15, 2026 05:57
… toward its timeout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s second doesn't move it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
What changes
Fixes three flaky tests: two integration tests, one in each tier, whose failures came from image pulls, and a unit test that failed on the CodeBuild run.
run_bundle_test's killed-run test (fast tier). Everyintegration-localfailure in the last 100 failed runs was this test (runs 43313173134, 43369378729, 43472071259 onmain, 43538837017), each withpublic.ecr.aws/nginx/nginx:stable-alpine … toomanyrequests: Rate exceeded. The test's container sandbox ran that image. A local sandbox pulls a plain tag every time, so each run made an anonymous ECR Public pull. The test now runs the registry image the job already holds (mirror.gcr.io/library/registry:2, the:5000service's), under its digest-pinned name (RepoDigests). A local sandbox doesn't pull an image it holds under a digest-pinned name. A machine without that image pulls it once, from mirror.gcr.io.A compose's pulls of its base take turns (slow tier, product fix). Run 43505816495 (
integration-local-slow (5/12), 2026-11-13) failed inbrowser_gateway_test's compose of the chromium env. The amd64 resolve failed withfailed to copy: … could not fetch content descriptor … not found. The arm64 platform check was running at the same moment.clock_desktop_teston the same runner then failed 30 s later withfailed to get reader from content store: content digest …: not found.composer.composebuilds pairs in threads, and both of these ran a container of the same base at once:docker create --platform linux/amd64 <base>builder._runs_here's emulation check:docker run --platform linux/arm64 <base>Either one pulls the base when Docker lacks it, and neither held the
image-pull:lock thathost_images.pullholds. On the containerd image store, the two pulls left the base's amd64 manifest without all its layers, so every later container of it on that runner failed. Both now hold that lock (host_images.pull_lock), so pulls of one image take turns across threads and processes. The slow tier'sMACHINE_LOCKSalready includeimage-pull:.user_chat_test'sget_timetest (unit). It set the gateway's clock with no rate, so it ran at 1, then expectedget_timeto answer the second it set. On #690's CodeBuild run it answered15:00:01Zfor15:00:00Z. It now sets the clock still, as the file's other tests do.Not covered: when a stored package lock lets a compose skip the resolve, BuildKit's own pull of the base in
docker builddoesn't take the lock. No CI failure has come from that path. An image already half-pulled by an earlier interrupted pull isn't repaired; this only stops our own concurrent pulls from making one.Testing
test_a_resolves_pull_of_its_base_takes_turns_with_a_platform_checks_and_a_deploys: a resolve, an arm64 platform check and a deploy'shost_images.pullof one base at once, against a fake Docker. At most one pull is in flight. It fails without the fix, and passed 6 times out of 6 with it.tst/unit/env/envs,tst/unit/providersandtst/unit/bundle: 4398 passed. The one failure there,test_disk_recipe's Windows install, fails the same way onmainon macOS (socat UNIX-CONNECT).ruff checkis clean.io.containerd.snapshotter.v1):mirror.gcr.io/library/registry@sha256:a3d8aaa6…browser_gateway_test.pyandclock_desktop_test.pytogether with-n 2 --dist loadfile, as the slow shard runs them: 5 passed, twice (274 s and 116 s). The one skip is the Playwright/Puppeteer test's, as onmain. Neither run's log shows a resolve, so these runs didn't exercise the race. The unit test above is what shows the lock holds.🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge; no new actionable issues were found.Summary
The PR makes local pulls of the same base image take turns and removes two test timing dependencies.
get_timetest keeps its virtual clock fixed.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD R[Resolve creates container] --> L[Shared image-pull lock] C[Platform check runs container] --> L D[Deploy pulls image] --> L L --> P[One pull at a time] R --> T[Lock wait counts toward resolve timeout]Reviews (7) · Last reviewed commit: "test(gateway): get_time's test sets the ..." · Reviewed by Greptile