From f700aa217fb58ed0832e7cdc2d7a8f78f12838f8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 21:43:48 +0000 Subject: [PATCH] Retry Docker registry push and manifest operations in release publish Docker Hub manifest push for :latest failed with a transient auth.docker.io timeout after the versioned tag had already been published. Add exponential backoff retries around docker push and docker manifest push. Co-authored-by: DevOps Rob --- .changelog/49.txt | 3 ++ .github/scripts/publish_docker_registries.sh | 31 ++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 .changelog/49.txt diff --git a/.changelog/49.txt b/.changelog/49.txt new file mode 100644 index 000000000..86c597eed --- /dev/null +++ b/.changelog/49.txt @@ -0,0 +1,3 @@ +```release-note:bug +ci: Retry flaky Docker registry push and manifest operations during release publish +``` diff --git a/.github/scripts/publish_docker_registries.sh b/.github/scripts/publish_docker_registries.sh index 636914c97..c7d6f5211 100755 --- a/.github/scripts/publish_docker_registries.sh +++ b/.github/scripts/publish_docker_registries.sh @@ -17,11 +17,36 @@ set -euo pipefail # PUBLISH_GHCR=false Skip GHCR (default: publish) # PUBLISH_ECR=false Skip ECR Public (default: publish) # PUBLISH_DOCKERHUB=false Skip Docker Hub (default: publish) +# RETRY_ATTEMPTS=5 Retries for docker push / manifest push (default: 5) +# RETRY_INITIAL_DELAY_SECS=4 Initial backoff seconds between retries (default: 4) function usage { echo "Usage: $0 " } +# Retry flaky registry operations (Docker Hub auth timeouts are common on manifest push). +function retry() { + local max_attempts="${RETRY_ATTEMPTS:-5}" + local delay="${RETRY_INITIAL_DELAY_SECS:-4}" + local attempt=1 + + while true; do + if "$@"; then + return 0 + fi + + if (( attempt >= max_attempts )); then + echo "ERROR: command failed after ${max_attempts} attempts: $*" >&2 + return 1 + fi + + echo "Attempt ${attempt}/${max_attempts} failed; retrying in ${delay}s: $*" >&2 + sleep "${delay}" + delay=$(( delay * 2 )) + attempt=$(( attempt + 1 )) + done +} + function publish_manifest() { local registry_prefix="$1" shift @@ -29,13 +54,13 @@ function publish_manifest() { docker manifest rm "${registry_prefix}:${version}" >/dev/null 2>&1 || true docker manifest create "${registry_prefix}:${version}" "${tags[@]}" - docker manifest push "${registry_prefix}:${version}" + retry docker manifest push "${registry_prefix}:${version}" echo "Published ${registry_prefix}:${version}" if [[ "${PUBLISH_LATEST:-false}" == "true" ]]; then docker manifest rm "${registry_prefix}:latest" >/dev/null 2>&1 || true docker manifest create "${registry_prefix}:latest" "${tags[@]}" - docker manifest push "${registry_prefix}:latest" + retry docker manifest push "${registry_prefix}:latest" echo "Published ${registry_prefix}:latest" fi } @@ -47,7 +72,7 @@ function publish_registry() { for arch in amd64 arm64; do local arch_tag="${registry_prefix}:${version}-${arch}" docker tag "${src_image}" "${arch_tag}" - docker push "${arch_tag}" + retry docker push "${arch_tag}" arch_tags+=( "${arch_tag}" ) done