Skip to content

Commit 8443fdb

Browse files
committed
workflows: chunk the external-download matrix across 4 parallel invocations
The `download` job in infrastructure-download-external.yml was hitting GitHub Actions' 256-entry `strategy.matrix` cap (259 configurations observed). Rather than trimming the matrix (which would drop legitimate arch × release combos users need) or duplicating a 500-line job block, lean on the fact that infrastructure-download-external.yml is *already* a reusable workflow — call it N times from the parent (infrastructure-repository-update.yml) with a `CHUNK_INDEX` / `CHUNK_COUNT` pair, and have the child filter its own matrix to its assigned slice. Child (infrastructure-download-external.yml): - Add CHUNK_INDEX (0..CHUNK_COUNT-1) and CHUNK_COUNT (default 1) inputs. - In the `start` job, after building MATRIX_JSON, slice the include[] list so each invocation keeps only entries where `index % CHUNK_COUNT == CHUNK_INDEX`. Modular slicing (not contiguous ranges) avoids clustering slow package types into one chunk. - Suffix the `assets-for-download` artifact name with CHUNK_INDEX so parallel uploads don't race against each other. Parent (infrastructure-repository-update.yml): - Turn the single `external:` reusable-workflow call into a `strategy.matrix` over `chunk_index: [0, 1, 2, 3]`, passing CHUNK_COUNT: 4 to the child. Effect: 4 parallel invocations, each with its own 256-matrix cap and its own `max-parallel=180`. Headroom 1024 total matrix entries, effective concurrency 720. Scale past that by bumping `chunk_index` list and CHUNK_COUNT in lockstep — no block duplication, no file extraction, no matrix trimming. Legacy/un-chunked callers that omit the chunk inputs get CHUNK_COUNT=1 and receive the entire matrix as before.
1 parent 360356c commit 8443fdb

2 files changed

Lines changed: 56 additions & 7 deletions

File tree

.github/workflows/infrastructure-download-external.yml

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ on:
4242
required: false
4343
type: boolean
4444
default: false
45+
CHUNK_INDEX:
46+
# Which slice of the matrix this invocation processes (0..CHUNK_COUNT-1).
47+
# Used to keep strategy.matrix under GitHub Actions' 256-entry cap when
48+
# the number of packages × arches × releases grows past that. Defaults
49+
# to 0/1 so the workflow still works when called un-chunked.
50+
required: false
51+
type: number
52+
default: 0
53+
CHUNK_COUNT:
54+
required: false
55+
type: number
56+
default: 1
4557
secrets:
4658
GPG_KEY1:
4759
required: true
@@ -209,7 +221,7 @@ jobs:
209221
- name: Upload Artifact
210222
uses: actions/upload-artifact@v7
211223
with:
212-
name: assets-for-download
224+
name: assets-for-download-${{ inputs.CHUNK_INDEX }}
213225
path: downloads
214226
overwrite: true
215227
retention-days: 5
@@ -360,11 +372,36 @@ jobs:
360372
echo "::warning::No matrix entries generated, adding placeholder" >&2
361373
MATRIX_JSON_COMPACTED='{"include":[{"name":"none","arch":"amd64","release":"bookworm"}]}'
362374
else
363-
# Debug: Show raw matrix JSON
364-
echo "::debug::Raw matrix JSON: ${MATRIX_JSON}" >&2
375+
# Chunk the matrix so each invocation keeps strategy.matrix
376+
# below GitHub Actions' 256-entry cap. Callers that don't
377+
# know about chunking get CHUNK_COUNT=1 and pass the whole
378+
# thing through (legacy behavior).
379+
CHUNK_INDEX="${{ inputs.CHUNK_INDEX }}"
380+
CHUNK_COUNT="${{ inputs.CHUNK_COUNT }}"
381+
if [[ "${CHUNK_COUNT}" -lt 1 ]]; then CHUNK_COUNT=1; fi
382+
if [[ "${CHUNK_INDEX}" -ge "${CHUNK_COUNT}" ]]; then
383+
echo "::error::CHUNK_INDEX=${CHUNK_INDEX} must be < CHUNK_COUNT=${CHUNK_COUNT}" >&2
384+
exit 1
385+
fi
365386
366-
# Compact the JSON for GitHub Actions
367-
MATRIX_JSON_COMPACTED=$(echo "${MATRIX_JSON}" | jq -c)
387+
# Slice jq: split includes into CHUNK_COUNT roughly-equal
388+
# groups by modular index (not contiguous ranges) so a
389+
# slow package type doesn't cluster into one chunk.
390+
SLICED=$(echo "${MATRIX_JSON}" | jq -c \
391+
--argjson idx "${CHUNK_INDEX}" \
392+
--argjson cnt "${CHUNK_COUNT}" \
393+
'{include: [.include | to_entries[] | select(.key % $cnt == $idx) | .value]}')
394+
395+
SLICE_COUNT=$(echo "${SLICED}" | jq '.include | length')
396+
echo "::notice::chunk ${CHUNK_INDEX}/${CHUNK_COUNT}: ${SLICE_COUNT} of ${MATRIX_COUNT} entries" >&2
397+
398+
# Empty slice needs a placeholder for the downstream job to
399+
# run at all — it'll skip entries with name=none.
400+
if [[ "${SLICE_COUNT}" -eq 0 ]]; then
401+
MATRIX_JSON_COMPACTED='{"include":[{"name":"none","arch":"amd64","release":"bookworm"}]}'
402+
else
403+
MATRIX_JSON_COMPACTED="${SLICED}"
404+
fi
368405
echo "::debug::Compacted matrix JSON: ${MATRIX_JSON_COMPACTED}" >&2
369406
fi
370407
@@ -897,5 +934,5 @@ jobs:
897934
- name: Clean artifacts
898935
uses: geekyeggo/delete-artifact@v6
899936
with:
900-
name: assets-for-download
937+
name: assets-for-download-${{ inputs.CHUNK_INDEX }}
901938
failOnError: false

.github/workflows/infrastructure-repository-update.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,18 @@ jobs:
4141
TEAM: "Release manager"
4242

4343
external:
44-
name: "Download external"
44+
name: "Download external (chunk ${{ matrix.chunk_index }}/4)"
4545
needs: Check
46+
# Fan out across 4 chunks. The child workflow filters its matrix to
47+
# only entries where `index % CHUNK_COUNT == CHUNK_INDEX`, so each
48+
# invocation stays under GitHub Actions' 256-entry strategy.matrix
49+
# cap. Effective concurrency is 4 × max-parallel (180) = 720.
50+
# Bump `chunk_index` and `CHUNK_COUNT` together when total packages
51+
# × arches × releases approaches 4 × 256 = 1024.
52+
strategy:
53+
fail-fast: false
54+
matrix:
55+
chunk_index: [0, 1, 2, 3]
4656
uses: armbian/armbian.github.io/.github/workflows/infrastructure-download-external.yml@main
4757
with:
4858
ENABLED: ${{ inputs.download_external != false || github.event.client_payload.download_external != false }}
@@ -51,6 +61,8 @@ jobs:
5161
BUILD_RUNNER: "docker"
5262
HOST_DEPLOY: "repo.armbian.com"
5363
PURGE: ${{ inputs.purge_external || false }}
64+
CHUNK_INDEX: ${{ matrix.chunk_index }}
65+
CHUNK_COUNT: 4
5466
secrets:
5567
GPG_KEY1: ${{ secrets.GPG_KEY3 }}
5668
GPG_KEY2: ${{ secrets.GPG_KEY4 }}

0 commit comments

Comments
 (0)