VPSSpark Blog
← Retour au journal de dev

GitHub Actions ralentit les équipes iOS — la vraie piste Xcode CI en 2026

Notes serveur · Cloud Mac CI #9 · 2026.06.12 · ~12 min de lecture
Carnet de bord : 47 minutes en file, split PR/Release, Cloud Mac, garde-fous Agent

Recherches : GitHub Actions iOS lent · file Xcode CI · runner macOS auto-hébergé · Cloud Mac

MacBook avec éditeur et terminal — une équipe iOS débugue la CI Xcode sur GitHub Actions
Un jeudi à 15 h sur Slack — « toujours en Queued » — classique pour les équipes iOS.

Jeudi 29 mai 2026, 15 h 03. Dans une équipe iOS de douze personnes, quelqu'un poste dans Slack #ios-ci le lien d'un run avec ce message : « En local, Xcode passe en douze minutes — le PR est encore en Queued. » Silence pendant une demi-heure : ce genre de ping, c'est le quotidien. Quarante-huit minutes plus tard, la même personne ajoute : « Queued 47m, run 12m. Pas de merge ce soir. » Un collègue du track Release sort d'une réunion, jette un œil à son téléphone : « L'Archive ios-release est toujours en file — la ligne PR est encore bloquée. »

Slack #ios-ci : développeur signale Queued 47 minutes, collègue Release indique la ligne Archive bloquée
fig. 5 · Extrait Slack #ios-ci (noms de dépôt et d'organisation masqués, heures et chiffres conservés)

Les captures proviennent de documents clients partagés lors du dépannage — anonymisés, chiffres intacts. Vous pouvez reproduire les stats via la doc GitHub sur le temps d'exécution des jobs et queue_wait_seconds.

Deux apps dans un monorepo, CI entièrement sur des runners macOS hébergés par GitHub. En 2025, ça passait ; au printemps 2026, la boucle de feedback s'allonge jusqu'à devenir insupportable. GitHub Actions n'est pas « cassé », mais pour les équipes iOS, ça ressemble de plus en plus à un bus partagé saturé aux heures de pointe.

2832s
queue_wait_seconds
724s
run duration
3.9×
queued / run

Ce jeudi-là : ouvrir la page Job — la barre jaune quatre fois plus longue que la verte

Ils nous ont envoyé une capture de la page Job du run #18472910356 — pas du bruit de couloir, une timeline avec des chiffres. Jaune (Queued) : 47 min 12 s, vert (Run) : 12 min 4 s, en bas de l'interface : queue_wait_seconds: 2832, run duration: 724. La formule est limpide : wait time >> run time.

Timeline GitHub Actions : Queued 47m12s, Run 12m4s, run 18472910356
fig. 1 · Run #18472910356 · ios-pr.yml · macos-latest · 2026-05-29 15:04 CST

En réunion, l'équipe débattait encore du parallélisme -jobs ou d'une nouvelle clé de cache DerivedData — sans avoir extrait les colonnes queued et run des dix derniers jobs macOS. Côté Release, c'était pire : ios-release.yml empilait xcodebuild archive, notarisation, upload TestFlight et tests unitaires PR sur la même ligne, le même label macos-latest. Un archive prend 25 à 40 minutes, monopolise des slots de concurrence rares et entraîne les jobs PR rapides dans la file.

Si vous voulez d'abord traiter le Queued, commencez par notre runbook de diagnostic file macOS runner. Le tournant est venu quand l'équipe a admis que le problème était la capacité — et a convaincu la salle avec des chiffres, pas des impressions.

Preuves : tableau recopié à la main de dix jobs failed

Avant le stand-up du 30 mai, quelqu'un a recopié dix jobs macOS failed depuis la liste Actions (voir fig. 3). Pas de BI — juste un tableau, deux colonnes clés : queued_s et run_s. Médiane queued 2650 s, run 724 s ; ratio jusqu'à 4,5×. Quelques secondes de silence en salle : plus personne n'accusait Xcode 17.4.

Tableau recopié à la main : queued_s et run_s de dix jobs macOS failed
fig. 3 · Tableau recopié : dix jobs macOS failed du 2026-05-22 au 05-29 (anonymisé)
Souvent pris pourSignal dans fig. 3Cause plus probable
Panne GitHub10/10 queued_s > run_sPlafond de concurrence macOS, jobs lourds qui bloquent les slots
Projet qui grossitrun_s stable entre 690–811sLa compilation n'est pas le goulot — l'attente, si
Pushes anarchiquesPlusieurs runs par PR (voir fig. 2)Boucle Agent / bot
Certificat expiréÉchecs de signature répartis sur plusieurs runsKeychain à froid, contention parallèle

fig. 2 : le même PR déclenché six fois

La file n'était que la première mi-temps. En mars, l'équipe avait branché un agent de code : CI rouge → lire les logs → commit auto → relancer Actions. La page Checks du PR #847 est explicite — six workflow runs, dont quatre par un bot, deux par des humains. Officiellement de la CI ; en pratique, une boucle de retry. Voir Ce qui se passe quand la CI devient une boucle.

Pull Request #847 : six exécutions de workflow GitHub Actions
fig. 2 · PR #847 · 6× ios-pr.yml (4× bot · 2× humain) · 2026-05-29

Plus tard, quelqu'un plaisanta : « La CI n'est pas morte — on l'a transformée en mouvement perpétuel. » Ce n'est pas l'automatisation qui pose problème, c'est que chaque fix bot grignote la file partagée sans pool de runners dédié.

Tournant : un Cloud Mac et la séparation des pipelines le 31 mai

Après le tableau, l'équipe a découpé les logs par type de job : environ 70 % de vérifs PR et builds d'intégration, 20 % de tests unitaires simulateur, 10 % d'archive et upload — proche de la composition mesurée d'une autre équipe à 500 CI iOS par jour. Idées : huit Mac mini ou migrer vers Xcode Cloud. Deux décisions ont été prises :

Le 31 mai : louer un Cloud Mac Apple Silicon, l'enregistrer en runner auto-hébergé (labels self-hosted, macOS, cloud-mac). L'expérience contrôle était simple : même commit, 50 builds sur macos-latest hébergé et sur le Cloud Mac — la variance queued passa de « parfois 40 minutes, parfois 5 » à « quasi toujours quelques secondes ».

Séparation des pipelines la même nuit. Archive, export et upload sortis de ios-pr.yml vers ios-release.yml ; la ligne PR ne garde que build et tests unitaires. Ajout d'un cron de warm-up : chaque nuit, xcodebuild build sur le Cloud Mac, DerivedData sur disque — plus fiable qu'un tirage froid depuis actions/cache à chaque run.

fig. 6 · Médiane du wall time de la même équipe (build PR, 50 runs sur deux semaines chacun)

macOS hébergé · queued
38 min
macOS hébergé · run
12 min
Cloud Mac auto-hébergé · queued
41 s
Cloud Mac auto-hébergé · run
9 min

Source : journaux d'expérience contrôle client (2026-05-31 — 06-08), recoupables avec fig. 1 et fig. 4.

9 juin : fig. 4 — enfin une page Job qui a du sens

Deux semaines après le split, lundi matin : dans Slack, capture du run #18510488201 — queued 41 s, run 9 min 17 s, runner self-hosted, cloud-mac. Pas de likes, juste une réaction — chez les équipes iOS, c'est le plus haut compliment.

GitHub Actions runner auto-hébergé : Queued 41s, Run 9m17s, cloud-mac
fig. 4 · Run #18510488201 · self-hosted, cloud-mac · 2026-06-09 09:11 CST

Garde-fous pour l'Agent : quatre règles dans le Wiki

Le split règle le blocage Archive sur les PR ; la boucle bot demande autre chose. Branche dédiée et pool de runners basse priorité pour le bot — merge après review humaine. Quatre règles figées dans le Wiki :

  • Workflow PR : pas d'archive / pas d'upload store
  • Jobs macOS avec concurrency pour éviter les runs empilés sur la même branche
  • Runners auto-hébergés étiquetés — pas de mélange avec des workflows expérimentaux
  • Push auto de l'Agent sur branche séparée, pas de push direct sur branches protégées
Auto-diagnostic en 30 minutes à copier
Ouvrez les 10 derniers jobs macOS, recopiez queue_wait_seconds et run duration (comme fig. 3) ; comptez les runs de workflow par PR (comme fig. 2) ; vérifiez si l'archive est encore dans le workflow PR. Si la médiane queued > run, parlez capacité runner avant les flags de compilation.

La nouvelle approche : garder GitHub, changer la capacité

L'expérience de cette équipe se résume en quatre actions que les équipes iOS déploient le plus en 2026 : pool de runners Cloud Mac auto-hébergés, split PR / Release, warm-up et cache disque, garde-fous Agent. Xcode Cloud remplace-t-il tout ? Adapté à l'écosystème Apple pur ; avec checks PR GitHub et pipelines Android mixtes, la plupart gardent Actions et déplacent seulement l'archive vers du macOS dédié.

Si votre équipe ressemble à…Recommandation courante
1–3 personnes, release hebdomacOS hébergé + cache agressif ; archive Release manuel
5–15 personnes, merge quotidien1–2 Cloud Mac auto-hébergés + split PR/Release
15+ personnes, plusieurs appsPool de runners par app (labels) + cron warm-up
Fixes Agent intensifsPool bot dédié + pas d'archive dans le workflow PR

La doc Apple xcodebuild insiste sur l'alignement scheme / destination ; si la CI repart à froid à chaque fois, « ça passe en local » perd son sens. Comme disait un client : mieux vaut rotation de certificats et gros upgrade Xcode que regarder une barre jaune de 47 minutes chaque jour.

En commençant par un premier runner Cloud Mac auto-hébergé

Si votre page Job ressemble à fig. 1 — jaune plus long que vert — le prochain investissement le plus rentable est souvent un Cloud Mac Apple Silicon dédié : enregistré comme runner GitHub auto-hébergé, le build PR passe de « loterie de file » aux neuf minutes prévisibles de fig. 4.

Deux semaines d'expérience contrôle : même branche, 50 builds sur macOS hébergé et Cloud Mac auto-hébergé — un tableau comme fig. 3. Les chiffres diront si c'est Xcode qui traîne ou la capacité qui freine le dev iOS.

Partez d'un Cloud Mac prévisible et remettez l'archive sur la ligne Release. Voir les offres Cloud Mac VPSSpark et enregistrer votre premier runner iOS auto-hébergé.

Offre limitée

CI iOS bloquée en file ? Un Cloud Mac en runner auto-hébergé

GitHub Actions · Apple Silicon dédié · split PR/Release

Accueil
Offre limitée Voir les plans