Fan-out двух платформ · уровни Gradle/CocoaPods/DerivedData · гейты очереди и откат на один узел
Небольшие команды, ведущие Flutter или React Native monorepo на нескольких узлах Mac Mesh, часто теряют wall time из‑за перетирания кэша, голодания очереди и межрегиональной подкачки зависимостей. В материале — матрица решений последовательная сборка / fan-out на два узла / выделенные раннеры по платформам, разнесение ключей Gradle, CocoaPods и DerivedData с границей «только чтение» для потребителей и шестишаговый воспроизводимый контур с откатом на один узел. Читайте вместе с affected-сборками monorepo и межрегиональным fan-out артефактов.
Параллельный Android и iOS — это не два независимых пайплайна на одной машине без модели ввода-вывода; неверный планировщик переносит нестабильность из компиляторов в планировщик задач. Когда проявляются сигналы ниже, возвращайтесь к матрице, а не наращивайте параллелизм вслепую.
Конкуренция Gradle и Xcode за диск: ~/.gradle и DerivedData растут на одном узле, ожидание IO доминирует в wall time.
Разрешение CocoaPods и дрейф Android NDK: отсутствие lockfile в ключах кэша даёт ложные попадания «зелёно на удалённом, красно на интеграции».
Metro и эмуляторы делят CPU: интерактивные проверки RN и ночной CI на общих ядрах — растёт глубина очереди при падающей пропускной способности.
Fan-out без рёбер «только чтение»: потребители перезаписывают общие префиксы и гоняются за сменой указателей на артефакты.
Межрегиональные вытягивания кэша без бюджета повторов: сетевые ретраи раздуваются и выедают параллельные слоты.
Измерения ориентированы на мобильные monorepo в мультирегиональном пуле удалённых Mac; цель — сделать fan-out проверяемым полем. Если в репозитории тяжёлые нативные модули, сначала согласуйте правила полного обхода с гайдом по affected-сборкам.
| Измерение | Предпочесть последовательность | Предпочесть dual fan-out | Разнести выделенные узлы |
|---|---|---|---|
| Форма изменения | Ассеты или правки текста одной платформы | Обе платформы меняют зависимости или бинарные поверхности синхронно | Android требует матрицу ABI, iOS — параллельные окна Archive |
| Состояние очереди | Стабильная глубина и предсказуемый P95 wall time | Сумма времени в очереди превышает выигрыш от fan-out | Archive на одной стороне блокирует проверку PR на другой |
| Политика кэша | Один префикс с lockfile и отпечатками toolchain в ключах | Раздельные префиксы с записью по платформам, потребители только чтение | Выделенные узлы — изолированные поколения и идентификаторы lease |
| Мультирегион | Один регион закрывает SLA | Primary пишет, спутники зеркалируют read-only | Спутники не должны перезаписывать ни один из префиксов |
| Откат | Слияние в последовательный режим при переполнении очереди или алертах диска | Заморозка fan-out после двух подряд провалов верификации | Эксклюзивность одной платформы на время крупных миграций Xcode или AGP |
Сначала зафиксируйте воспроизводимые входы, затем обсуждайте параллелизм двух платформ; обратный порядок превращает параллелизм в параллельные отказы.
Предполагается, что раннеры проходят аутентификацию на каждом узле с доверием общего пула; если артефакты расходятся между океанами, добавьте поля манифеста и lease из гайда по fan-out артефактов.
Зафиксировать пятикомпонентный входной пакет: короткий хэш коммита, Podfile.lock/Gemfile.lock, lock Gradle, вывод xcodebuild -version и мажорные версии Android SDK/NDK в заголовке пайплайна.
Разделить префиксы с записью: держите IOS_CACHE_GEN и AND_CACHE_GEN монотонными; не используйте один каталог с записью для обеих платформ.
Решить fan-out: стройте параллельный граф задач только если ячейка матрицы требует dual fan-out; иначе оставайтесь последовательными.
Пишет primary, потребители только чтение: архивы пишут только primaries; потребители проверяют хэш и размер до распаковки.
Бюджеты очереди: экспоненциальная задержка с жёстким потолком на сетевые ошибки; сверх потолка — инцидент и освобождение слотов.
Откат на один узел: при порогах по диску или очереди автоматически схлопывайте в последовательный режим и помечайте FANOUT_DISABLED для постмортемов.
IOS_KEY="${CI_COMMIT_SHORT_SHA}:pods:${PODFILE_LOCK_SHA}:$(xcodebuild -version | shasum -a 256 | cut -c1-10)"
AND_KEY="${CI_COMMIT_SHORT_SHA}:gradle:${GRADLE_LOCK_SHA}:${ANDROID_SDK_MAJOR}"
export FASTLANE_SKIP_UPDATE_CHECK=1
echo "{\"ios\":\"$IOS_KEY\",\"android\":\"$AND_KEY\"}" > "${CI_PROJECT_DIR}/dual-cache.manifest"
Заметка: поля ключа можно заменить кастомным манифестом под ваш стек; сохраняйте монотонные поколения и префиксы с записью по платформам, не пересобирайте граф зависимостей на потребителях.
Числа ниже — отправная точка для ревью и ёмкости; подменяйте их реальными гистограммами сборок и метриками очереди, не трактуйте как внешний SLA. В постмортемах фиксируйте вместе dual-platform P95, время распаковки tarball и длительность удержания слота.
FANOUT_DISABLED и ручной разбор вместо нового параллелизма.| Сигнал команды | Стартовая стратегия | Связь с fan-out артефактов |
|---|---|---|
| Единицы контрибьюторов | Один регион, последовательная dual-platform плюс локальные кэши | Низкая потребность в fan-out, проще ключи |
| PR из нескольких регионов | Primary пишет оба префикса, спутники read-only | Жёсткая связка с rsync или объектным хранилищем |
| Ночные пакеты ИИ-агентов | Выделенные узлы под тяжёлую компиляцию, отдельно от интерактивных пулов | Снижает риск раздувания общих пространств ключей ночными задачами |
Внимание: межрегиональный fan-out до перевода потребителей в режим только чтение усиливает полусинхронизацию до одновременных ложных зелёных.
Ноутбуки с одновременными Android-эмуляторами и iOS Archive регулярно теряют время на сон, блокировку экрана и джиттер канала; чистые SaaS-фермы мобильных сборок часто упираются в нативную отладку и корпоративную сетевую политику. Командам, которым нужны непрерывная поставка на две платформы и аудируемые роли узлов в одной истории ёмкости, самосборные стеки часто теряют наблюдаемость и границы прав.
Командам, которым нужны контрактные узлы, предсказуемый канал и выбор региона, обычно выгоднее критичные dual-platform сборки на заказываемых облачных Mac с явной политикой очереди. Для кроссплатформенной поставки вместе с ночной нагрузкой ИИ-агентов аренда облачных Mac mini у VpsMesh как правило лучше стыкуется с задачей: узлы разделяются чисто, связи остаются проверяемыми, параллелизм измеряется так же однозначно, как глубина очереди.
Включайте fan-out, когда обе ноги растягивают wall time, видна конкуренция за диск или CPU между emulator и xcodebuild на одном узле, либо глубина очереди держится выше порога; при изменениях одной платформы оставайтесь последовательными. Дополнительная логика отсечения — в материале по affected-сборкам monorepo.
Общий префикс с записью без изоляции не использовать; уровни ключей и каталогов с единственным писателем и потребителями только для чтения. Для межрегионального fan-out см. матрицу fan-out артефактов.
Страница цен аренды Mac mini M4, оформление заказа Mac mini M4 и справочный центр по удалённому доступу и сети — до онбординга и покупки.