From df34eafb5becd5b308c9c227d9892ecf99734d8d Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Sun, 31 May 2026 03:22:13 +0200 Subject: [PATCH 1/2] Prevent reserved-but-empty base venv cache via `fail-fast: false` The `prepare-base` matrix saves the base venv cache per Python version. With the default `fail-fast: true`, a failing leg (e.g. a prerelease that can't resolve dependencies) cancels the sibling legs. If a sibling is mid-way through `actions/cache/save`, the cache key gets reserved but the upload never completes, leaving it stuck and unrestorable on later runs. Disable `fail-fast` so a failing leg no longer cancels its siblings, letting each base venv cache save run to completion. --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7426af..9c69763 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,10 @@ jobs: name: Prepare base dependencies runs-on: ubuntu-latest strategy: + # Don't cancel sibling matrix jobs if one fails. A cancelled + # `actions/cache/save` step can leave a cache key reserved but + # unpopulated, which then can't be restored or re-saved. + fail-fast: false matrix: python-version: ${{ fromJSON(format('[{0}]', inputs.PYTHON_MATRIX)) }} steps: From 3caa3101c2a9a23af732f63dfa1e0d07ca327112 Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Sun, 31 May 2026 03:23:03 +0200 Subject: [PATCH 2/2] Protect base venv cache save against cancellation Replace the previous `fail-fast: false` approach with a more targeted fix that mirrors home-assistant/core (PR #168310). `fail-fast: false` only stops matrix-internal cancellation and forces every leg to run to completion. Instead, guard the cache save step itself with `always()` so an in-flight `actions/cache/save` survives any cancellation source -- `fail-fast` from a sibling leg or a concurrency cancel -- and finishes its upload rather than leaving the cache key reserved but unpopulated. The default `fail-fast` behavior is restored. Gate the save on the `create-venv` step's success (via a new `id`) so a failed or cancelled venv build is never cached. --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c69763..2c3e56e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,10 +46,6 @@ jobs: name: Prepare base dependencies runs-on: ubuntu-latest strategy: - # Don't cancel sibling matrix jobs if one fails. A cancelled - # `actions/cache/save` step can leave a cache key reserved but - # unpopulated, which then can't be restored or re-saved. - fail-fast: false matrix: python-version: ${{ fromJSON(format('[{0}]', inputs.PYTHON_MATRIX)) }} steps: @@ -77,6 +73,7 @@ jobs: with: enable-cache: false - name: Create Python virtual environment + id: create-venv if: steps.cache-venv.outputs.cache-hit != 'true' env: AIOHTTP_NO_EXTENSIONS: 1 @@ -98,7 +95,12 @@ jobs: uv pip install pytest-xdist fi - name: Cache base Python virtual environment - if: steps.cache-venv.outputs.cache-hit != 'true' + # Use `always()` so a cancellation (e.g. fail-fast from a sibling + # matrix job, or a concurrency cancel) cannot interrupt the save + # mid-upload and leave the cache key reserved but unpopulated. + # Guard on `create-venv` success so a failed/cancelled venv build + # is never cached. + if: always() && steps.create-venv.outcome == 'success' uses: actions/cache/save@v5 with: path: .venv