From 78248ba7d9adc425764885ff904cdfdffdb07251 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 7 Aug 2026 11:40:42 -0400 Subject: [PATCH] Move `env:pull` auto-retry logic to `docker.js`. --- .../workflows/reusable-phpunit-tests-v3.yml | 17 +------ tools/local-env/scripts/docker.js | 44 ++++++++++++++----- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/.github/workflows/reusable-phpunit-tests-v3.yml b/.github/workflows/reusable-phpunit-tests-v3.yml index 6a7f49fba468c..35bba41de68bc 100644 --- a/.github/workflows/reusable-phpunit-tests-v3.yml +++ b/.github/workflows/reusable-phpunit-tests-v3.yml @@ -205,21 +205,8 @@ jobs: run: | docker -v - - name: Pull Docker images (with retry) - run: | - for attempt in 1 2 3; do - if npm run env:pull; then - break - fi - - if [ "$attempt" -eq 3 ]; then - echo "npm run env:pull failed after $attempt attempts." - exit 1 - fi - - echo "npm run env:pull failed (attempt $attempt); retrying..." - sleep $(( attempt * 10 )) - done + - name: Pull Docker images + run: npm run env:pull - name: Start Docker environment run: | diff --git a/tools/local-env/scripts/docker.js b/tools/local-env/scripts/docker.js index c7b11f0058424..6a4bd157689e1 100644 --- a/tools/local-env/scripts/docker.js +++ b/tools/local-env/scripts/docker.js @@ -25,17 +25,39 @@ if ( dockerCommand.includes( 'cli' ) && dockerCommand.includes( 'db' ) && ! dock dockerCommand.push( '--defaults' ); } +const composeArgs = [ + 'compose', + ...composeFiles + .map( ( composeFile ) => [ '-f', composeFile ] ) + .flat(), + ...dockerCommand, +]; + +// Failures during image pulls are re-attempted to rule out registry rate limits and network issues. +const maxAttempts = 'pull' === dockerCommand[0] ? 3 : 1; + // Execute any Docker compose command passed to this script. -const returns = spawnSync( - 'docker', - [ - 'compose', - ...composeFiles - .map( ( composeFile ) => [ '-f', composeFile ] ) - .flat(), - ...dockerCommand, - ], - { stdio: 'inherit' } -); +let returns; +for ( let attempt = 1; attempt <= maxAttempts; attempt++ ) { + returns = spawnSync( 'docker', composeArgs, { stdio: 'inherit' } ); + + if ( 0 === returns.status ) { + break; + } + + if ( attempt === maxAttempts ) { + if ( maxAttempts > 1 ) { + console.log( `\ndocker compose ${ dockerCommand[0] } failed after ${ attempt } attempts.` ); + } + + break; + } + + const delay = attempt * 10; + console.log( `\ndocker compose ${ dockerCommand[0] } failed (attempt ${ attempt } of ${ maxAttempts }). Retrying in ${ delay } seconds...\n` ); + + // Sleep synchronously so the retry loop stays in order without going async. + Atomics.wait( new Int32Array( new SharedArrayBuffer( 4 ) ), 0, 0, delay * 1000 ); +} process.exit( returns.status );