Мобильные релизы тормозят, если один Mac гоняет все UI-тесты последовательно. В этом гайде — когда окупается шардирование, сравнение одного узла и распределённого парка в одной матрице, контракт меток runner и бюджетов времени, а также восемь шагов, как разнести XCTest UI по выделенным облачным Mac mini M4 с предсказуемой математикой очередей.
Если вы стандартизируетесь на самохостных runner’ах GitHub Actions, шардирование превращает «один быстрый Mac» в парк, который успевает проверить pull request до того, как ревьюеры переключат контекст. Для более широкого параллелизма сборки см. параллельные Mac-узлы для CI/CD.
Почему даже мощный Mac не попадает в SLA по UI-тестам
Xcode агрессивно параллелит unit-тесты, но UI-тесты тратят время на запуск симуляторов, анимации и ожидание SpringBoard — нагрузка нелинейно растёт с числом ядер на одном хосте.
- Конкуренция за GPU симулятора: три UI-сьюта одновременно на M4 часто выводят кадры за порог 33 мс, из-за чего тапы становятся нестабильными и падают ложные тесты.
- Раздувание диска: каждый шард дублирует запись DerivedData; без 500 ГБ+ запаса на SSD параллельные джобы рушатся, когда свободно меньше ~15 %.
- Непрозрачная очередь: без меток на шард непонятно, медленный PR из-за UI-инфраструктуры или сборки — перепроцаривают compile-runner’ы и всё равно не укладываются в UI.
Матрица решений: один Mac против шардированного парка
| Критерий | Один M4 «всё в одном» | Выделенные Mac под UI-шарды |
|---|---|---|
| Wall-clock для UI-сьюта 90 мин | Серия ≈ 90 мин | 3 шарда ≈ 35–40 мин при балансе |
| Чувствительность к флакам | Высокая под нагрузкой | Ниже при одном сьюте на машину |
| Сложность эксплуатации | Низкая | Средняя; нужны метки и дашборды |
| Лучшая география | Любая | Шарды в HK / JP / KR / SG / US рядом с разработчиками |
Разбейте тесты на корзины до закупки железа
Шардирование — это планирование, замаскированное под инфраструктуру. Делите сьюты на корзины со сопоставимой дисперсией длительности — цель ±20 % от медианы, чтобы один шард не был вечным аутсайдером.
- Экспортируйте историю длительностей из Xcode Cloud, логов XCTest или БД CI; сортируйте по p95.
- Выделите тяжёлые login-сценарии в отдельную корзину, чтобы не блокировать checkout и настройки, которые можно гонять параллельно.
- Помечайте тесты с физическими лабораториями отдельно — облачные Mac mini сильны в симуляторах, не в USB-фермах.
- Ограничивайте размер корзины бюджетом PR; если корзина всё ещё дольше 25 минут, делите по фиче-модулю.
- Версионируйте карту корзин в Git (
ui-shards.json) для воспроизводимых перезапусков.
Совет: Держите compile- и UI-шарды на разных метках. Смешивание даёт сюрпризы в очередях, когда тяжёлый xcodebuild test забирает машину с таймаутами под симулятор.
Контракт меток runner для UI-шардов
| Набор меток | Назначение | Пример runs-on |
|---|---|---|
| self-hosted, macOS, m4, ios-compile | Только сборка + unit-тесты | [self-hosted, macOS, m4, ios-compile] |
| self-hosted, macOS, m4, ios-ui, shard-1 | UI-корзина A | [self-hosted, macOS, m4, ios-ui, shard-1] |
| self-hosted, macOS, m4, ios-ui, shard-2 | UI-корзина B | Тот же шаблон для B/C/D … |
Матрица GitHub Actions без случайного двойного планирования
Часто шарды задают измерением matrix. Типичный провал: и shard: [1,2,3], и широкий runs-on, попадающий на все Mac — GitHub может посадить несколько шардов на один хост и свести на нет бюджет на железо. Привяжите каждую ветку матрицы к уникальной метке или переменным репозитория 1:1 к hostname.
matrix:
shard: [1, 2, 3]
include:
- shard: 1
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-1]
- shard: 2
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-2]
- shard: 3
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-3]
jobs:
ui-tests:
runs-on: ${{ matrix.runner_labels }}
timeout-minutes: 40
Добавьте правило репозитория, отклоняющее workflow без метки shard-* на UI-джобах — одна политика спасает от добровольного схлопывания параллелизма. Арендуя Mac mini во втором регионе (например Сингапур при ревьюерах в Токио), дублируйте схему меток по региону (shard-1-sg), чтобы близость сети была явной в YAML.
Восемь шагов: UI-шарды на облачном Mac mini M4
Предполагается SSH к хостам Mac mini M4 NodeMac. Паттерны подключения — в справочном центре.
- Выделите N машин: целевое число шардов плюс один горячий резерв под flaky-перезапуски.
- Одинаковые сборки Xcode и runtime симуляторов заранее; дрейф между шардами даёт ложные «у меня на runner прошло».
- Регистрируйте GitHub runner’ы с уникальными именами и только нужной меткой шарда.
timeout-minutesв workflow — стартуйте с 40 для UI и ужимайте по p95.- Передавайте id шарда в
xcodebuildчерез схемы или тест-планы (списки-only-testingна корзину). - Отключите сон экрана и обеспечьте GUI-сессии для CI-пользователя, если это требует harness; зафиксируйте в security review.
- Складывайте артефакты централизованно (JUnit, скриншоты) с именем шарда в файле для триажа.
- Алерт на перекос: если один шард на 1,5× дольше остальных три прогона подряд — перебалансируйте корзины.
KPI и SLO для шардированного парка
Без метрик шардирование превращается в слепую закупку железа. Задайте SLO на «PR с зелёным UI» (например p95 меньше 45 минут) и измеряйте отдельно ожидание в очереди runner, чистое время тестов и загрузку артефактов. Дашборды по метке ios-ui покажут, не хватает ли шардов или корзины перегружены.
Еженедельный разбор десяти самых медленных тестов часто выгоднее нового Mac. Узлы NodeMac в Гонконге, Японии, Корее, Сингапуре и США снижают сетевую задержку; сочетайте региональные runner’ы с расчётом очереди выше вместо складывания всего в один часовой пояс.
Складывайте JUnit и сводки по шардам в тот же бэкенд артефактов, что и unit-тесты, чтобы видеть тренды за недели. Если p95 резко подскочил, сопоставьте с обновлениями Xcode или macOS на хостах шардов — это чаще даёт скрытые регрессии, чем свежие коммиты в приложении.
FAQ
Сколько шардов UI-тестов помещается на один Mac mini M4?
Считайте каждый тяжёлый по симулятору UI-шард основным заданием на машину, если нет замеров запаса; два шарда возможны для лёгких наборов, но конкуренция за GPU и диск часто съедает выигрыш по wall-clock.
Нужно ли шардам те же метки runner, что и чисто сборочным джобам?
Нет—используйте отдельные метки вроде ios-ui-shard, чтобы сборочные джобы не забирали машины с дополнительными симуляторами и предположениями о GUI-сессии.
Нужны машины в нескольких минутах от команд в Гонконге, Токио, Сеуле, Сингапуре или США? Сравните тарифы NodeMac, чтобы согласовать число шардов с логикой очереди, а не гадать.
Mac mini M4 — практичная единица шардирования для iOS UI: Apple Silicon даёт сильный single-thread для XCTest, unified memory под несколько сервисов симулятора и эффективный простой между всплесками PR. NodeMac сдаёт в аренду выделенные физические Mac mini с SSH и VNC в HK, JP, KR, SG и US — каждый шард это реальное железо для удалённой отладки. Аренда по требованию снижает CapEx, пока вы проверяете карту шардов и балансируете корзины по телеметрии.