VPSSpark Блог
← К дневнику разработки

GitHub Actions тормозит iOS-команды — рабочее решение для Xcode CI в 2026

Заметки из дата-центра · Cloud Mac CI #9 · 2026.06.12 · ~12 мин чтения
Полевой отчёт: 47 минут Queued, split пайплайнов, Cloud Mac, ограждения для Agent

Запросы: GitHub Actions iOS медленно · очередь Xcode CI · self-hosted macOS runner · Cloud Mac

MacBook с редактором и терминалом — iOS-команда разбирает Xcode CI в GitHub Actions
Четверг, 15:03 в Slack — «всё ещё Queued» — знакомо многим iOS-командам.

Четверг, 29 мая 2026, 15:03. В iOS-команде из двенадцати человек в Slack #ios-ci появляется ссылка на run с текстом: «Локально в Xcode прошло за двенадцать минут — PR всё ещё в Queued.» Полчаса тишины — такие сообщения привычны. Через 48 минут та же строка: «Queued 47m, run 12m. Сегодня merge не ждите.» Коллега из release-трека выходит из переговорки, смотрит в телефон: «ios-release Archive всё ещё в очереди — PR-линия снова забита.»

Slack #ios-ci: разработчик сообщает Queued 47 минут, release-коллега — заблокированная Archive-PR-линия
рис. 5 · Фрагмент Slack #ios-ci (имена репозитория и организации скрыты, время и цифры сохранены)

Скриншоты — материалы клиента при разборе инцидента, с маскировкой; цифры не менялись. Статистику можно воспроизвести по документации GitHub о времени выполнения job и queue_wait_seconds.

Два приложения в одном monorepo, CI целиком на macOS runner'ах GitHub. В 2025 терпимо; к весне 2026 цикл обратной связи растянулся до потери терпения. GitHub Actions не «сломан», но для iOS-команд всё больше похоже на переполненный маршрутный автобус в час пик.

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

Тот четверг: открыть страницу Job — жёлтая полоса в четыре раза длиннее зелёной

Прислали скрин страницы Job run #18472910356 — не пересказ, а таймлайн с цифрами. Жёлтый (Queued): 47 мин 12 с, зелёный (Run): 12 мин 4 с, внизу UI: queue_wait_seconds: 2832, run duration: 724. Формула проста: wait time >> run time.

Таймлайн GitHub Actions Job: Queued 47m12s, Run 12m4s, run 18472910356
рис. 1 · Run #18472910356 · ios-pr.yml · macos-latest · 2026-05-29 15:04 CST

На встрече обсуждали параллель -jobs и ключ кэша DerivedData — но никто не выгрузил queued и run по последним десяти macOS job'ам. На release-линии хуже: ios-release.yml совмещал xcodebuild archive, notarization, загрузку в TestFlight и unit-тесты PR в одной линии на том же macos-latest. Archive — 25–40 минут, занимает редкие слоты concurrency и тащит в очередь быстрые PR-job'ы.

Если нужно сначала разобраться с Queued, начните с нашего runbook диагностики очереди macOS runner. Перелом наступил, когда команда признала: проблема в ёмкости — и убедила зал цифрами, а не ощущениями.

Доказательства: таблица из десяти failed job'ов, переписанная вручную

Перед stand-up 30 мая кто-то вручную переписал десять failed macOS job'ов из списка Actions (см. рис. 3). Без BI — таблица с двумя ключевыми столбцами: queued_s и run_s. Медиана queued 2650 с, run 724 с; отношение до 4,5×. Несколько секунд тишины: больше никто не винил Xcode 17.4.

Таблица вручную: queued_s и run_s десяти failed macOS job'ов
рис. 3 · Таблица вручную: десять failed macOS job'ов с 2026-05-22 по 05-29 (обезличено)
Часто принимают заСигнал на рис. 3Вероятнее причина
Сбой GitHub10/10 queued_s > run_sЛимит concurrency macOS, тяжёлые job'ы держат слоты
Рост проектаrun_s стабильно 690–811sКомпиляция не главный фактор — ожидание
Хаотичные push'иНесколько run'ов на один PR (см. рис. 2)Цикл Agent / bot
Истёкший сертификатОшибки подписи разбросаны по разным run'амХолодный keychain, параллельная конкуренция

рис. 2: один PR запустили шесть раз

Очередь — только первая половина. В марте подключили coding Agent: CI красный → читать логи → auto-commit → снова Actions. Страница Checks PR #847 наглядна — шесть workflow run'ов, четыре от bot, два от людей. Формально CI; по факту retry loop. Подробнее: Что происходит, когда CI превращается в цикл.

Pull Request #847: шесть запусков workflow GitHub Actions
рис. 2 · PR #847 · 6× ios-pr.yml (4× bot · 2× человек) · 2026-05-29

Позже в команде пошутили: «CI не умер — мы сделали из него вечный двигатель.» Плохо не автоматизация, а то, что каждый bot-fix забирает общую очередь без выделенного пула runner'ов.

Перелом: Cloud Mac и split пайплайнов в ночь на 31 мая

После таблицы разложили логи по типам job'ов: ~70 % PR-проверок и интеграционных сборок, ~20 % unit-тестов на симуляторе, ~10 % archive и upload — почти как у другой команды с 500 iOS CI в день. Предлагали восемь Mac mini или Xcode Cloud. В итоге два шага:

31 мая: аренда Cloud Mac на Apple Silicon, регистрация как self-hosted runner (labels self-hosted, macOS, cloud-mac). Контрольный эксперимент простой: один commit, по 50 сборок на hosted macos-latest и на Cloud Mac — дисперсия queued с «то 40 минут, то 5» сжалась до «обычно единицы секунд».

Split пайплайнов той же ночью. Archive, export и upload из ios-pr.yml в ios-release.yml; PR-линия только build и unit-тесты. Плюс warm-up cron: каждую ночь xcodebuild build на Cloud Mac, DerivedData на диске — надёжнее, чем каждый раз холодный старт из actions/cache.

рис. 6 · Медиана wall time той же команды (PR build, по 50 run'ов за две недели)

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

Источник: логи контрольного эксперимента клиента (2026-05-31 — 06-08), сверяется с рис. 1 и рис. 4.

9 июня: рис. 4 — наконец страница Job «как надо»

Через две недели после split, утро понедельника: в Slack скрин run #18510488201 — queued 41 с, run 9 мин 17 с, runner self-hosted, cloud-mac. Без лайков, только реакция — для iOS-команд это высшая похвала.

GitHub Actions self-hosted runner: Queued 41s, Run 9m17s, cloud-mac
рис. 4 · Run #18510488201 · self-hosted, cloud-mac · 2026-06-09 09:11 CST

Ограждения для Agent: четыре правила в Wiki

Split снял блокировку Archive на PR; bot loop потребовал отдельных мер. Bot — отдельная ветка и пул runner'ов с низким приоритетом, merge после human review. Четыре жёстких правила в Wiki:

  • PR workflow: без archive / без загрузки в store
  • macOS job'ы с concurrency, чтобы одна ветка не копила run'ы
  • Self-hosted runner'ы с labels — не смешивать с экспериментальными workflow
  • Auto-push Agent только в отдельную ветку, без прямого push в protected branches
Самопроверка за 30 минут — можно копировать
Откройте последние 10 macOS job'ов, выпишите queue_wait_seconds и run duration (как на рис. 3); посчитайте workflow run'ы на PR (как на рис. 2); проверьте, не остался ли archive в PR workflow. Если медиана queued > run — сначала ёмкость runner'ов, не флаги компиляции.

Новый подход: не отказываться от GitHub, а сменить ёмкость

Опыт команды сводится к четырём вещам, которые iOS-команды чаще всего внедряют в 2026: пул Cloud Mac self-hosted runner'ов, split PR / Release, warm-up и disk cache, ограждения для Agent. Заменяет ли Xcode Cloud? Хорош для чистого Apple-стека; с GitHub PR checks и смешанной Android-линией большинство оставляет Actions и переносит только archive на выделенный macOS.

Если команда похожа на…Типичная рекомендация
1–3 человека, релиз раз в неделюHosted macOS + сильный cache; archive Release вручную
5–15 человек, merge каждый день1–2 Cloud Mac self-hosted + split PR/Release
15+ человек, несколько app'овПул runner'ов с labels по app + warm-up cron
Много auto-fix от AgentОтдельный bot pool + без archive в PR workflow

В документации Apple xcodebuild подчёркивается согласованность scheme и destination; если CI каждый раз стартует с холодной среды, «локально проходит» теряет смысл. Как сформулировал клиент: лучше ротация сертификатов и major-upgrade Xcode, чем каждый день смотреть на жёлтую полосу 47 минут.

С первого Cloud Mac self-hosted runner

Если страница Job как на рис. 1 — жёлтое длиннее зелёного — следующая разумная инвестиция обычно выделенный Cloud Mac на Apple Silicon: зарегистрированный как GitHub self-hosted runner, PR-сборка перестаёт быть «лотереей очереди» и становится предсказуемыми девятью минутами с рис. 4.

Две недели контрольного эксперимента: одна ветка, по 50 сборок на hosted macOS и Cloud Mac self-hosted — таблица как на рис. 3. Цифры покажут, тормозит Xcode или ёмкость iOS-разработку.

Начните с предсказуемого Cloud Mac и верните archive на release-линию. Тарифы VPSSpark Cloud Mac и регистрация первого iOS self-hosted runner.

Ограниченное предложение

iOS CI вечно в Queued? Cloud Mac как self-hosted runner

GitHub Actions · выделенный Apple Silicon · split PR/Release

На главную
Акция Смотреть тарифы