VPSSpark standard de diagnostic file CI (Cloud Mac CI #2). Ordre de lecture : Hook → formule → symptômes → Failure Model → Hard Rules → Runbook → FAQ. Liens : #1 capacité · #5 incident de scale · #3 TCO self-hosted · #8 vitesse de build.
1 · Hook : l’insight qui surprend
Dans la plupart des incidents macOS CI en queued, le problème n’est pas « il nous manque des Mac »—c’est L2 (Archive) qui tourne sur la voie PR. En prod, neuf tickets sur dix collent à ce schéma.
Sur Slack, on lit vite « la CI est lente ». Dans GitHub Actions, Queued et In progress ne mesurent pas la même chose. Sans poser « le temps d’attente écrase-t-il le temps d’exécution ? », on monte Xcode ou on achète des minutes—aucun des deux ne vide la file des runners. Ce billet fixe la norme pour ce triage.
2 · Cœur : une seule formule
Tout ce qui suit déplie ce test unique. À coller tel quel dans le wiki on-call.
Formule maîtresse
CI queue problem ⇔ wait time >> run time
Lecture ingénieur : macOS runner queued signale une saturation du pool de runners, pas un Xcode plus lent.
Formule fausse → hors sujet ici ; voir #8 (Xcode / cache). Vraie → Failure 3 Layer Model et CI Hard Rules.
Beaucoup d’équipes FR mélangent macos-latest hébergé et self-hosted et voient « des minutes restantes mais Queued ». C’est la confusion entre minutes (facturation) et concurrency (slots simultanés). N’ajustez pools et triggers que si la formule est vraie.
3 · Symptôme : Queued ≠ Running
Dans GitHub Actions, Queued veut dire : le job est dans le workflow mais n’a pas encore de slot runner. Sous In progress, checkout, xcodebuild et signature tournent. Une PR rouge d’une heure est souvent « compile lente »—la timeline affiche 52 minutes d’attente, 11 minutes d’exécution.
Mauvais réflexes : monter Xcode, augmenter timeout-minutes, acheter des minutes GitHub. Le temps Queued ne rentre souvent pas dans le timeout que vous croyez avoir réglé.
Mesurer avec le temps d’exécution des jobs (queue_wait_seconds vs durée de run). Un P95 hebdo détecte la Trigger Explosion avant le rush de merge du vendredi.
| temps d’attente | temps d’exécution | |
|---|---|---|
| UI | Queued | In progress |
| Goulot | GitHub Actions macOS runner queue / self-hosted runner queue | Xcode · signature · upload |
| Mauvais fix | plus de minutes · nouveau Xcode | cache (→ #8) |
Quand l’équipe parle DerivedData alors que le badge reste longtemps en Queued, l’observation est au mauvais endroit du pipeline. Dans le runbook, journalisez attente et exécution séparément—sinon vous rachetez le mauvais levier.
4 · Explication : CI Queue Failure 3 Layer Model
Si wait time >> run time, la cause est l’une de ces couches SRE (ou leur empilement).
| Couche | Sens | Signaux | Aujourd’hui |
|---|---|---|---|
| Capacity Limit | Plateforme · macos-latest |
Seul l’hébergé macOS runner queued ; minutes ≠ concurrency | Réduire le fanout ; sortir Archive de l’hébergé → #3 |
| Pool Misdesign | Architecture · self-hosted | Archive sur PR ; fast/archive partagés ; un runner bloque tout | Hard Rules → #1 #6 |
| Trigger Explosion | Charge · fanout workflow | matrix / paths / workflows dupliqués ; jobs > runners | Resserer les triggers → #5 |
Capacity Limit — touche les runners macOS hébergés et le plafond de concurrency macOS de l’org (limites). Pool Misdesign — cause racine fréquente : L2 sur PR, pools mélangés. Trigger Explosion — corriger le YAML, pas le hardware. (Couches Failure ≠ tiers L0/L1/L2.)
Les trois couches ne s’excluent pas : vendredi soir, matrix en hausse (Trigger), Archive qui monopolise fast (Pool), quota hébergé à sec (Capacity)—le « triple » du cas 20 personnes #5 revient souvent. Commencez par la colonne Signaux.
5 · Correctif : CI Hard Rules (MUST NOT à respecter)
Langage normatif pour le runbook—pas des suggestions. Une violation = incident.
Rule 1: PR MUST NOT run L2 Rule 2: L2 MUST run on isolated pool (macos-archive) Rule 3: fast pool MUST remain unblocked (fast ≠ archive) # Mapping PR → L0 + L1 only →macos-fastmain → L2 only →macos-archive
Référence des tiers de jobs (implémentation des Hard Rules uniquement) :
| Tier | Travail | Pool | Règles |
|---|---|---|---|
| L0 | Build module, lint, tests légers | macos-fast |
Rule 1 · OK sur PR |
| L1 | Intégration PR, tests simulateur | macos-fast |
Rule 1 · MUST NOT Archive |
| L2 | Archive, IPA, TestFlight | macos-archive |
Rules 2+3 · PR MUST NOT |
« Juste une Archive sur la PR » semble anodin—38 minutes de L2 sur un label bloquent tous les L0/L1 en Queued. Les exceptions cassent le design de pool ; basculez la release sur main / schedule.
Fig. 1 · Pool Misdesign : L2 occupe le slot → tous les jobs macOS en queued
jobs: pr-fast: if: github.event_name == 'pull_request' runs-on: [self-hosted, macos-fast] release-archive: if: github.ref == 'refs/heads/main' || github.event_name == 'schedule' runs-on: [self-hosted, macos-archive]
Topologie runners : pool élastique vs always-on · #1 dimensionnement · file saine → #3.
6 · Runbook : une page (on-call)
0. CI queue problem ⇔ wait time >> run time ? ─No→ #8
1. Layer: Capacity | Pool Misdesign | Trigger Explosion
2. MUST: Rule1 PR no L2 · Rule2 L2 isolated · Rule3 fast unblocked
3. PR workflow has no archive/export/upload ?
4. wait P95 < 8min → then size runners (#3)
En une phrase : La plupart des queued macOS CI viennent de L2 sur la voie PR—not d’un manque de machines. macOS runner queued = saturation du pool ; wait >> run, puis Failure Model, puis Hard Rules.
En post-mortem, « on a acheté des runners » sans Rule 1–3 dans le dépôt reproduit l’incident. Une case PR « pas de job Archive » fait baisser les récidives.
7 · FAQ
Pourquoi les runners macOS filent plus souvent ?
Capacity Limit (plafond de concurrency) + Pool Misdesign (L2 sur PR). Commencez par wait >> run.
Problème de file ou build lent ?
CI queue problem ⇔ wait time >> run time. Vrai → pool ; faux → #8.
Pourquoi du queued en self-hosted ?
Pool Misdesign : la self-hosted runner queue suit vos labels et la topologie. Violer les Hard Rules bloque la file—un Mac cloud ne répare pas un mauvais YAML.
Minutes GitHub Actions vs concurrency ?
minutes = facturation ; concurrency = slots simultanés. Plus de minutes ne débloquent pas macOS runner queued.
C’est un problème de pool de runners ?
wait >> run + un self-hosted occupé longtemps → Pool Misdesign ; seul macos-latest queued → Capacity Limit. Voir Runbook.
File OK mais build encore lent ?
#8 (vitesse). Dimensionnement : #1. Croissance d’équipe : #5.
Valider le split de pools : besoin d’un PoC fast pool ?
Après les Hard Rules, pour sortir L0/L1 de la GitHub Actions macOS runner queue hébergée, lancez un runner macos-fast et vérifiez wait time P95 < 8 min avant d’ajouter macos-archive selon #1.
Pour un fast pool isolé au quotidien sans changer le réseau du bureau : offres Mac cloud ou accueil VPSSpark—validation de topologie seulement ; les règles restent obligatoires. TCO : série #3.