VPSSpark Blog
← Zurück zum Dev-Tagebuch

GitHub Actions bremst iOS-Teams aus — die Xcode-CI-Lösung, die 2026 wirklich half

Server-Notizen · Cloud Mac CI #9 · 2026.06.12 · ~12 Min. Lesezeit
Praxisbericht: 47 Minuten Queue, Pipeline-Split, Cloud Mac, Agent-Leitplanken

Suche: GitHub Actions iOS langsam · Xcode CI Warteschlange · Self-hosted macOS Runner · Cloud Mac

MacBook mit Editor und Terminal — iOS-Team analysiert GitHub Actions Xcode CI
Donnerstag 15 Uhr in Slack — „noch Queued“ — kennen die meisten iOS-Teams.

Donnerstag, 29. Mai 2026, 15:03 Uhr. In einem zwölfköpfigen iOS-Team landet in Slack #ios-ci ein Run-Link mit dem Satz: „Lokal in Xcode zwölf Minuten durch — der PR hängt noch in Queued.“ Eine halbe Stunde lang kommt nichts — solche Meldungen kennt man. Nach 48 Minuten folgt die Ergänzung: „Queued 47m, Run 12m. Heute Abend kein Merge mehr.“ Ein Kollege aus dem Release-Track schaut vom Meeting aufs Handy: „Der ios-release-Archive-Job steht noch in der Queue — die PR-Linie ist wieder blockiert.“

Slack #ios-ci: Entwickler meldet Queued 47 Minuten, Release-Kollege berichtet blockierte Archive-PR-Linie
Abb. 5 · Auszug aus Slack #ios-ci (Repo- und Organisationsnamen geschwärzt, Zeiten und Zahlen unverändert)

Die Screenshots stammen aus Kundenmaterial, das uns bei der Fehlersuche zur Verfügung stand — geschwärzt, Zahlen unverändert. Die Statistik lässt sich anhand der GitHub-Dokumentation zu Job-Ausführungszeit und queue_wait_seconds selbst nachvollziehen.

Zwei Apps in einem Monorepo, CI vollständig auf GitHub-gehosteten macOS-Runnern. 2025 ging das noch — im Frühjahr 2026 wurde der Feedback-Loop so lang, dass man die Geduld verliert. GitHub Actions ist nicht „kaputt“, aber für iOS-Teams fühlt es sich zunehmend wie ein überfüllter Pendelbus in der Rushhour an.

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

Dieser Donnerstag: Job-Seite öffnen — gelber Balken viermal so lang wie grün

Sie schickten uns einen Screenshot der Job-Seite von Run #18472910356 — kein Hörensagen, sondern eine Timeline mit harten Zahlen. Gelb (Queued): 47 Min. 12 Sek., Grün (Run): 12 Min. 4 Sek., unten im UI: queue_wait_seconds: 2832, run duration: 724. Die Formel ist brutal einfach: wait time >> run time.

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

Im Meeting diskutierte das Team noch, ob man -jobs parallelisieren oder den DerivedData-Cache-Key anpassen soll — aber niemand hatte die letzten zehn macOS-Jobs nach queued- und run-Spalten ausgewertet. Auf der Release-Seite war die Lage noch frustrierender: ios-release.yml packte xcodebuild archive, Notarisierung, TestFlight-Upload und PR-Unit-Tests in dieselbe Pipeline auf demselben macos-latest-Label. Ein Archive dauert 25–40 Minuten, blockiert knappe Concurrency-Slots und zieht schnelle PR-Feedback-Jobs mit in die Warteschlange.

Wenn du jetzt nur die Queued-Zeit angehen willst, starte mit unserem macOS-Runner-Queue-Diagnose-Runbook. Der Wendepunkt kam, als das Team akzeptierte, dass das Problem bei der Kapazität liegt — und das Meeting mit Zahlen statt Bauchgefühl überzeugte.

Belege: Handkopierte Tabelle aus zehn failed Jobs

Vor dem Stand-up am 30. Mai kopierte jemand zehn failed macOS-Jobs aus der Actions-Liste ab (siehe Abb. 3). Kein BI-Dashboard — nur eine Tabelle mit zwei Kernspalten: queued_s und run_s. Median queued 2650 Sek., run 724 Sek.; das Verhältnis stieg bis 4,5×. Ein paar Sekunden Stille im Meeting: Niemand sprach mehr davon, dass Xcode 17.4 schuld sei.

Handkopierte Statistiktabelle: queued_s und run_s von zehn failed macOS-Jobs
Abb. 3 · Handkopierte Tabelle: zehn failed macOS-Jobs vom 2026-05-22 bis 05-29 (anonymisiert)
Oft fälschlich gedachtSignal in Abb. 3Wahrscheinlichere Ursache
GitHub-Ausfall10/10 queued_s > run_smacOS-Concurrency-Cap, Schwergewichts-Jobs blockieren Slots
Projekt wächstrun_s stabil bei 690–811sCompile ist nicht der Engpass — Warten schon
Chaotische PushesMehrere Runs pro PR (siehe Abb. 2)Agent-/Bot-Schleife
Abgelaufenes ZertifikatSignaturfehler über verschiedene Runs verteiltKeychain-Cold-Start, parallele Konkurrenz

Abb. 2: Derselbe PR wurde sechsmal getriggert

Queue war nur die erste Hälfte. Im März hatte das Team einen Coding-Agent angebunden: CI rot → Logs lesen → automatischer Commit → Actions erneut. Die Checks-Seite von PR #847 zeigt es deutlich — sechs Workflow-Runs, davon vier mit Bot-Actor, zwei menschlich. Formal noch CI; faktisch eine Retry-Schleife. Mehr dazu in Was passiert, wenn CI zur Endlosschleife wird.

Pull Request #847: sechs GitHub Actions Workflow-Runs
Abb. 2 · PR #847 · 6× ios-pr.yml (4× Bot · 2× Mensch) · 2026-05-29

Später sagte jemand im Team scherzhaft: „CI ist nicht tot — wir haben es zum Perpetuum mobile gemacht.“ Das Problem ist nicht die Automatisierung, sondern dass jeder Bot-Fix die gemeinsame Queue belastet — ohne dedizierten Runner-Pool.

Wendepunkt: ein Cloud Mac und der Pipeline-Split am 31. Mai

Nach der Handtabelle zerlegten sie die Logs nach Job-Typ: etwa 70 % PR-Checks und Integrations-Builds, 20 % Simulator-Unit-Tests, 10 % Archive und Upload — fast identisch mit der Zusammensetzung eines anderen Teams mit 500 iOS-CI-Runs pro Tag. Vorschläge reichten von acht Mac minis bis Xcode Cloud. Am Ende setzten sie zwei Dinge um:

Am 31. Mai: Apple-Silicon-Cloud-Mac mieten, als Self-hosted Runner registrieren (Labels self-hosted, macOS, cloud-mac). Das Gegenexperiment war schlicht: derselbe Commit, je 50 Builds auf gehostetem macos-latest und auf dem Cloud Mac — die Queued-Varianz schrumpfte von „mal 40 Minuten, mal 5“ auf „meist einstellige Sekunden“.

Pipeline-Split in derselben Nacht. Archive, Export und Upload aus ios-pr.yml nach ios-release.yml; die PR-Linie nur noch build plus Unit-Tests. Dazu ein Warm-up-Cron: täglich nachts xcodebuild build auf dem Cloud Mac, DerivedData bleibt auf der Platte — stabiler als jedes Mal aus actions/cache kalt zu starten.

Abb. 6 · Median Wall Time derselben Mannschaft (PR-Build, je 50 Läufe über zwei Wochen)

Gehostetes macOS · queued
38 min
Gehostetes macOS · run
12 min
Cloud Mac self-hosted · queued
41 s
Cloud Mac self-hosted · run
9 min

Datenquelle: Kunden-Gegenexperiment-Logs (2026-05-31 — 06-08), querverifizierbar mit Abb. 1 und Abb. 4.

9. Juni: Abb. 4 — endlich eine Job-Seite, die Sinn ergibt

Zwei Wochen nach dem Split, Montagmorgen: In Slack landet ein Screenshot von Run #18510488201 — queued 41 Sek., run 9 Min. 17 Sek., Runner self-hosted, cloud-mac. Kein Applaus, nur ein Emoji — in iOS-Teams ist das das höchste Lob.

GitHub Actions Self-hosted Runner: Queued 41s, Run 9m17s, cloud-mac
Abb. 4 · Run #18510488201 · self-hosted, cloud-mac · 2026-06-09 09:11 CST

Leitplanken für den Agent: vier Regeln im Wiki

Der Pipeline-Split löste das Archive-Problem auf der PR-Linie; die Bot-Schleife brauchte eigene Maßnahmen. Der Bot bekam einen separaten Branch und einen Runner-Pool mit niedrigerer Priorität — Merge erst nach menschlichem Review. Vier harte Regeln im Wiki:

  • PR-Workflow: kein Archive / kein Store-Upload
  • macOS-Jobs mit concurrency, damit derselbe Branch nicht stapelt
  • Self-hosted Runner mit Labels — kein Mischen mit Experiment-Workflows
  • Agent-Auto-Push nur auf separatem Branch, kein Direkt-Push auf geschützte Branches
30-Minuten-Selbstcheck zum Mitnehmen
Öffne die letzten 10 macOS-Jobs, notiere queue_wait_seconds und run duration (wie Abb. 3); zähle Workflow-Runs pro PR (wie Abb. 2); prüfe, ob Archive noch im PR-Workflow steckt. Ist der Median queued > run, zuerst Runner-Kapazität — nicht Compile-Flags.

Die neue Lösung: GitHub behalten, Kapazität wechseln

Die Erfahrung dieses Teams lässt sich auf vier Punkte reduzieren, die iOS-Teams 2026 am häufigsten umsetzen: Cloud-Mac-Self-hosted-Runner-Pool, PR/Release-Split, Warm-up und Disk-Cache, Agent-Leitplanken. Ersetzt Xcode Cloud das? Gut für reine Apple-Ökosystem-Workflows; mit GitHub-PR-Checks und gemischten Android-Linien behalten die meisten Actions und verlagern nur Archive auf dedizierte macOS-Kapazität.

Wenn euer Team eher so aussieht …Typische Empfehlung
1–3 Personen, wöchentliche ReleasesGehostetes macOS + starker Cache; Release-Archive manuell
5–15 Personen, tägliche Merges1–2 Cloud-Mac-Self-hosted + PR/Release-Split
15+ Personen, mehrere AppsRunner-Pool nach App labeln + Warm-up-Cron
Agent-lastige Auto-FixesEigener Bot-Pool + kein Archive im PR-Workflow

Apples xcodebuild-Dokumentation betont Konsistenz von Scheme und Destination; bei jedem Cold Start in CI verliert „lokal grün“ an Bedeutung. Ein Kunde formulierte es so: Lieber Zertifikatsrotation und Xcode-Major-Upgrades als jeden Tag 47 Minuten gelben Balken anstarren.

Vom ersten Cloud-Mac-Self-hosted-Runner an

Wenn eure Job-Seite wie Abb. 1 aussieht — gelb länger als grün — ist die nächste sinnvolle Investition meist ein dedizierter Apple-Silicon-Cloud-Mac: als GitHub-Self-hosted-Runner registriert, wird PR-Build von „Queue-Lotterie“ zu den vorhersagbaren neun Minuten aus Abb. 4.

Zwei Wochen Gegenexperiment: derselbe Branch, je 50 Builds auf gehostetem macOS und Cloud-Mac-Self-hosted — eine Tabelle wie Abb. 3. Die Zahlen zeigen, ob Xcode langsam ist oder die Kapazität iOS ausbremst.

Mit einem vorhersagbaren Cloud Mac starten und Archive zurück auf die Release-Linie legen. VPSSpark Cloud-Mac-Tarife ansehen und den ersten iOS-Self-hosted-Runner registrieren.

Zeitlich begrenzt

iOS-CI hängt in der Queue? Cloud Mac als Self-hosted Runner

GitHub Actions · dediziertes Apple Silicon · PR/Release-Split

Zur Startseite
Angebot Tarife ansehen