Hold Pull Request macOS Builds Until a Runner Is Free

A pull request's macOS build now waits in one repo-wide line, from a
Linux job, until the macOS runners every active Build all run holds or
still needs leave two free. A run is let in whole: its first arch takes
both runners and its second goes straight through, since letting arches
in one at a time deadlocks with every runner held by a run waiting for
its other arch. Push, nightly and manual runs reserve two runners until
their macOS work is done, and a pull request run keeps its two until its
universal build and tests finish, so jobs that never pass the line are
accounted for. Queued jobs count as busy. API errors and a four-hour
limit let the build in rather than block it.

Co-authored-by: raistlin7447 <kris.austin@gmail.com>
This commit is contained in:
Hanif Koh
2026-10-11 05:49:13 +08:00
co-authored by raistlin7447
parent d208e45736
commit 9f25c89994
3 changed files with 467 additions and 2 deletions
+31 -2
View File
@@ -131,10 +131,39 @@ jobs:
key: ${{ needs.check_cache.outputs.cache-key }}
lookup-only: true
# Hosted macOS runners are scarce, so a pull request's macOS build waits until
# one is free that push and nightly builds do not need. See the script.
macos_admission:
name: Wait for a macOS runner
needs: [check_cache, wait_for_deps]
if: ${{ !cancelled() && needs.check_cache.result == 'success' && startsWith(inputs.os, 'macos-') && github.event_name == 'pull_request' }}
runs-on: ubuntu-24.04
env:
WAIT_MINUTES: 240
# Must exceed WAIT_MINUTES.
timeout-minutes: 250
# One line for every arch of every pull request, and only its first job polls.
concurrency:
group: macos-admission
queue: max
steps:
- name: Checkout
uses: actions/checkout@v7
with:
sparse-checkout: scripts/ci_macos_admission.py
sparse-checkout-cone-mode: false
- name: wait for a macOS runner
env:
GH_TOKEN: ${{ github.token }}
MACOS_RUNNER_LIMIT: ${{ vars.MACOS_RUNNER_LIMIT }}
run: python3 scripts/ci_macos_admission.py
build_deps: # call next step
name: Build Deps
needs: [check_cache, wait_for_deps]
# A failed wait counts as no cache, so the deps are built here.
needs: [check_cache, wait_for_deps, macos_admission]
# A failed wait counts as no cache, so the deps are built here. A failed
# admission still builds rather than skip macOS.
if: ${{ !cancelled() && needs.check_cache.result == 'success' }}
uses: ./.github/workflows/build_deps.yml
with: