From 45333467a8a085bbf37d6c60d490760c986c0de2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 21 Aug 2026 13:13:19 -0400 Subject: [PATCH 1/2] ci: Pull the warm-test images in parallel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The five mirrored images were pulled one after another, so the step cost the sum of five pulls — a median 29s on every host shard, which at 20 shards is ten minutes of machine time per run for work the daemon can do concurrently. Pull them together and wait. Each pull's output is captured and replayed in a fixed order afterwards: interleaved progress from five images is unreadable exactly when someone is trying to see which mirror failed. `warm` already downgrades a miss to a warning and falls back to Docker Hub, so no failure semantics change here. Co-Authored-By: Claude Opus 5 --- .github/actions/warm-test-images/action.yml | 37 ++++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/.github/actions/warm-test-images/action.yml b/.github/actions/warm-test-images/action.yml index 80b6ad703f9..812828b40d7 100644 --- a/.github/actions/warm-test-images/action.yml +++ b/.github/actions/warm-test-images/action.yml @@ -50,8 +50,35 @@ runs: echo "::warning::could not warm $canonical from GHCR mirror; falling back to Docker Hub" } - warm matrixdotorg/synapse:v1.126.0 synapse:v1.126.0 - warm rnwood/smtp4dev:v3.1 smtp4dev:v3.1 - warm postgres:16.3 postgres:16.3 - warm ghcr.io/navikt/mock-oauth2-server:4.0.1 mock-oauth2-server:4.0.1 - warm caddy:2.10.2-alpine caddy:2.10.2-alpine + # Pull the five in parallel. They are distinct images, so the daemon + # fetches them concurrently and the step costs about as much as the + # slowest one instead of the sum; every shard pays this, so the + # difference is machine-hours across a run. Each pull's output goes to + # its own file and is replayed in a fixed order afterwards, because + # interleaved `docker pull` progress from five images is unreadable + # exactly when someone is trying to work out which mirror failed. + warm_bg() { + log="$(mktemp)" + logs+=("$log") + warm "$1" "$2" >"$log" 2>&1 & + pids+=($!) + } + + logs=() + pids=() + warm_bg matrixdotorg/synapse:v1.126.0 synapse:v1.126.0 + warm_bg rnwood/smtp4dev:v3.1 smtp4dev:v3.1 + warm_bg postgres:16.3 postgres:16.3 + warm_bg ghcr.io/navikt/mock-oauth2-server:4.0.1 mock-oauth2-server:4.0.1 + warm_bg caddy:2.10.2-alpine caddy:2.10.2-alpine + + # `warm` never fails (it downgrades a miss to a warning), so nothing + # here needs to inspect exit status — but wait on each pid rather than + # bare `wait` so a future warm that does fail can be noticed. + for pid in "${pids[@]}"; do + wait "$pid" || true + done + for log in "${logs[@]}"; do + cat "$log" + rm -f "$log" + done From 3eef91b9e963891f72b9c110194679f381bee24e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 21 Aug 2026 14:30:16 -0400 Subject: [PATCH 2/2] Re-run CI for a second measurement of the parallel image warm The first run showed the warm step dropping 29s to 13s while the readiness wait grew 1s to 38s. One sample cannot separate that from machine-speed drift, and the run's shards were slower across the board. Co-Authored-By: Claude Opus 5