-parallel-testing-enabled, число destination, параллельный Simulator и рост каталогов Derived Data. Ниже — компактная матрица решений, обязательные блокировки сборки, соглашение о путях и чек-лист водяных знаков для накопителей 1 ТБ и 2 ТБ.
Три узких места параллельного тестирования между регионами
Команда покупает второй узел в другой площадке и ожидает линейного ускорения, но стенка часов растёт: CoreSimulator конкурирует за память и файловый слой, несколько destination в одном процессе не дают выигрыша, а общий том с индексами ловит гонки записи. Эти эффекты не лечатся одной галочкой в пайплайне — нужен регламент лимитов и дисковой приёмки.
- Параллелизм Xcode: включённый parallel testing распределяет работу по destination, но не отменяет стоимость поднятия рантаймов и IO кэша.
- Simulator: одновременно загруженные устройства и UI‑сьюиты съедают RAM быстрее, чем растёт счётчик destination в командной строке.
- Диск 1 ТБ / 2 ТБ: несколько версий Xcode и снимки тестов заполняют том нелинейно; без порогов очистки очередь джобов встаёт внезапно.
Параметры: -parallel-testing-enabled, число destination и бюджет Simulator
Держите два независимых рычага: верхнюю границу destination на один вызов xcodebuild и отдельный лимит параллельных Simulator на узел, включая соседние джобы. Межрегиональную задержку компенсируйте горизонтальным масштабом узлов, а не бесконечным раздуванием destination в одной задаче.
-parallel-testing-enabled |
Количество destination (на один процесс) | Параллельный Simulator (бюджет узла) |
|---|---|---|
| NO (одиночный прогон) | 1, один аргумент -destination |
1–2 загруженных рантайма; для тяжёлого UI оставьте один активный симулятор. |
| YES, преимущественно юнит‑тесты | 2–3, один SDK и близкие версии рантайма | 2–3 без перекрывающихся снапшот‑сьютов; число одновременных джобов на Mac ограничьте отдельно. |
| YES, смесь UI и скриншотов | не выше 2; масштабирование — дополнительными узлами | 2 фиксированно плюс мониторинг памяти; при джиттере сети приоритет — воспроизводимость, а не пиковая степень параллелизма. |
Для дросселирования событий ФС и Git на монорепо см. матрицу Watchman и диска; при общей базе на томе — SQLite WAL и очередь писателей.
Блокировка сборки: один писатель на критический каталог
Одновременная запись нескольких агентов в один Derived Data или каталог продуктов даёт повреждённые индексы и «плавающие» падения тестов. Планировщик очереди дополняйте короткой критической секцией на файловой системе: классический flock вокруг promote и синхронизации артефактов. Не кладите сетевые вызовы внутрь блокировки.
LOCK_FILE="/var/tmp/xcode-derived-publish.lock"
flock -n "$LOCK_FILE" bash -c '
xcodebuild -scheme "$SCHEME" -parallel-testing-enabled YES test
rsync -a "$LOCAL_DERIVED/Build/Products/" "/Volumes/CIArtifacts/$BUILD_ID/"
' || { echo "lock busy"; exit 17; }
Слой меток и аффинити в оркестраторе согласуйте с Nomad, аффинити и двухуровневым build lock; для выноса бинарников между площадками остаётся канон из матрицы rsync и promote.
Путь Derived Data: локальный каталог против общего кэша
Рабочий шаблон — -derivedDataPath на быстром локальном APFS с суффиксом идентификатора джобы, а общий том использовать преимущественно для чтения кэшей модулей или уже собранных артефактов. Запись на сетевой том без жёстких гарантий блокировок исключайте из горячего пути xcodebuild.
- Переменные CI: уникальный подкаталог на прогон, удаление только после зелёного артефакта.
- Simulator: отдельная метрика размера рантаймов и данных CoreSimulator, не смешивать с общим счётчиком свободного места без разбивки.
- Публичные справочники: конфигурации памяти и площадок сверяйте на странице тарифов до выбора лимитов parallel testing.
Пороги очистки диска: приёмка для накопителей 1 ТБ и 2 ТБ
Чем шире parallel testing, тем быстрее растут промежуточные продукты и несколько поколений рантаймов Simulator. Процентные водяные знаки одинаково применимы к одному и двум терабайтам: на 2 ТБ запас больше, но и объём «мусора» со временем догоняет ту же жёлтую зону, если не автоматизировать удаление.
| Занятое место | Линия 1 ТБ | Линия 2 ТБ |
|---|---|---|
| до 70% | xcrun simctl delete unavailable, старые каталоги DerivedData, временные каталоги агента по расписанию. |
Те же правила; не откладывайте уборку из‑за кажущегося запаса. |
| 70–80% (жёлтая зона) | План расширения тома или переноса артефактов в текущем спринте; снизить верхний предел destination. | Сначала уменьшить число одновременных джобов и Simulator, затем инфраструктуру. |
| 80–90% | Остановить новые тяжёлые UI‑сьюиты и полные пересборки до стабилизации; сузить rsync‑окно. | Проверить дубликаты рантаймов Xcode; удалить неиспользуемые версии. |
| свыше 90% (красная зона) | Немедленно блокировать новые веера тестов, поднимать узел или диск, вывести водяной знак на дашборд мониторинга круглосуточно. | |
Пять шагов внедрения на кластере clustervps
- Зафиксировать лимиты. Запишите в runbook максимум destination на джобу и максимум Simulator на узел, согласуйте с памятью выбранного тарифа.
- Развести пути. Включите уникальный
-derivedDataPathи запретите совместную запись без flock. - Смоделировать нагрузку. Прогоните типовой спринт с parallel testing на одном узле, замерьте пик памяти и рост тома за сутки.
- Подключить мониторинг. Алерты по проценту заполнения APFS и отдельно по каталогу CoreSimulator.
- Закрепить откат. При серии таймаутов Simulator временно вернитесь к одному destination и увеличьте число узлов вместо тонкой настройки флага.
Краткий FAQ
Destination растёт, а wall‑clock нет: упёрлись в Simulator или диск; делите сьюиты по узлам.
Частые «lock busy»: слишком широкая критическая секция; сужайте область flock до publish.
Два терабайта, но снова жёлтая зона: накопились версии Xcode и рантаймы; чистите неиспользуемое до снижения параллелизма.
Аренда Mac mini M4 под Xcode CI между регионами
Оформите узлы с достаточной памятью и диском под ваш лимит Simulator, сравните планы на странице тарифов и откройте справочный центр для сетевого доступа и типовых вопросов.