From 7d1b2d0d2ca4e9f23841dbbc746cdef4bb089985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 22 Oct 2026 23:54:15 +0200 Subject: [PATCH] ci: cache and bound the Linux desktop dependency install Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/linux.yml | 76 ++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 17 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 005ed7d1eb..cd8384b586 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -64,9 +64,24 @@ jobs: # Unbounded, this step could not fail — it could only stall. On 2026-08-19 a slow mirror # held apt past the job's 30-minute budget on four main-branch runs and several unrelated # PRs, which reported as a red check on branches that never ran a line of project code. - # Two bounds fix that: apt retries and times out each mirror request itself (a blip - # self-heals without a manual re-run), and `timeout-minutes` is the backstop for a mirror - # that drips bytes slowly enough to defeat the socket timeout. + # On 2026-10-22 it recurred: the step took 20-60s normally, but 10 of 73 runs hit the + # 6-minute backstop. The Azure mirror appears to be a pull-through cache. A package nobody + # else requested recently (poppler-data, fonts-urw-base35, pulled in by gnome-calculator) + # is fetched from a slow upstream on first request, and the download crawls or stalls. The + # retry that warmed the mirror then succeeded in seconds, which is why re-runs were green. + # Three bounds fix that: the downloaded .debs are cached so most runs never ask the mirror + # for them, a download that does stall is dropped and retried under a per-attempt deadline + # (apt resumes with the files already fetched), and `timeout-minutes` stays as the + # backstop. dpkg itself never runs under a deadline. + - name: Restore Linux desktop package archives + id: apt-archives + if: steps.impact.outputs.run != 'false' + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.2.3 + with: + path: ~/apt-archives + key: apt-archives-${{ runner.os }}-${{ hashFiles('.github/workflows/linux.yml') }} + restore-keys: apt-archives-${{ runner.os }}- + - name: Install Linux desktop dependencies if: steps.impact.outputs.run != 'false' timeout-minutes: 6 @@ -79,22 +94,49 @@ jobs: # The runner's own unattended-upgrades timer holds the dpkg lock; wait, don't hang. -o DPkg::Lock::Timeout=60 ) - printf 'APT update start (UTC): %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" - sudo apt-get update "${APT_OPTS[@]}" - printf 'APT update complete (UTC): %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" - printf 'APT install start (UTC): %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" - sudo apt-get install -y "${APT_OPTS[@]}" \ - xvfb \ - xdotool \ - scrot \ - at-spi2-core \ - python3-gi \ - gir1.2-atspi-2.0 \ - libatk-adaptor \ - dbus-x11 \ - gnome-calculator \ + PACKAGES=( + xvfb + xdotool + scrot + at-spi2-core + python3-gi + gir1.2-atspi-2.0 + libatk-adaptor + dbus-x11 + gnome-calculator wmctrl + ) + # Retry a network phase under a per-attempt deadline. + apt_bounded() { + local seconds="$1" + shift + for attempt in 1 2 3; do + printf 'APT %s attempt %s start (UTC): %s\n' "$1" "$attempt" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" + if sudo timeout --kill-after=5 "$seconds" apt-get "$@" "${APT_OPTS[@]}"; then + return 0 + fi + done + echo "::error::apt-get $1 did not finish within ${seconds}s on 3 attempts" + return 1 + } + mkdir -p ~/apt-archives + sudo cp -n ~/apt-archives/*.deb /var/cache/apt/archives/ 2>/dev/null || true + apt_bounded 30 update + apt_bounded 75 install -y --no-install-recommends --download-only "${PACKAGES[@]}" + printf 'APT install start (UTC): %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" + sudo apt-get install -y --no-install-recommends "${APT_OPTS[@]}" "${PACKAGES[@]}" printf 'APT install complete (UTC): %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" + # Drop archives for versions the index no longer offers so the cache cannot grow. + sudo apt-get autoclean -q + rm -f ~/apt-archives/*.deb + cp /var/cache/apt/archives/*.deb ~/apt-archives/ + + - name: Save Linux desktop package archives + if: steps.impact.outputs.run != 'false' && steps.apt-archives.outputs.cache-hit != 'true' + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.2.3 + with: + path: ~/apt-archives + key: apt-archives-${{ runner.os }}-${{ hashFiles('.github/workflows/linux.yml') }} - name: Start Xvfb and D-Bus if: steps.impact.outputs.run != 'false'