Команда разработчиков сравнивает метрики эффективности GitHub Actions и собственных Mac-узлов CI

На ревью миграции руководство задаёт один вопрос: «Если уйти с GitHub Actions на собственные Mac-узлы — насколько вырастет эффективность разработки?» Ответ «сборка чуть быстрее» редко убеждает. В 2026 мы проводили A/B с несколькими iOS-, Flutter- и React Native-командами: после перехода на self-hosted Mac (офисный Mac mini, bare metal или Cloud Mac с runner) главный выигрыш — не компилятор, а исчезновение очереди и ожидания. Ниже — четыре типа метрик, три реальных сравнительные таблицы, двухнедельный чеклист миграции и грубый ROI.

Источник данных: анонимизированные миграции Q4 2025–Q2 2026 (команды 8–35 человек, Swift / Kotlin Multiplatform / RN). Железо в основном M4 16 ГБ и M4 Pro 24 ГБ. Подставьте размер своего репозитория — актуально на 2026-07-20.

Quick Answer: насколько быстрее?

Что важноHosted macOS runner (до)Собственный Mac-узел (после)Типичный выигрыш
PR до зелёной галочки (end-to-end)42–68 мин9–16 мин~70–80% короче
Ожидание в очереди15–45 мин/запуск0–2 минпочти ноль
Один Archive-build11–14 мин8–11 мин~15–25% (с кэшем)
Сборок TestFlight за релизную ночь1–23–5пропускная способность ~2–3×
Пассивное ожидание/нед/разработчик3–6 чел·ч0,5–1,2 чел·ч~75% меньше

Коротко: главный рост — в ожидании, а не в «ускорении компилятора». Собственный узел выводит дефицитный macOS-пул из shared queue; плюс персистентный DerivedData — и получаются цифры из таблицы.

Сначала мерить, потом говорить «насколько»

После миграции многие говорят «почти не быстрее», потому что смотрят только job duration в GitHub Actions и игнорируют queue time и ожидание в Slack. Две недели до и после — минимум четыре показателя:

  • Очередь: секунды от job queued до job started, P50 / P95
  • PR-цикл: последний push до всех required checks зелёные
  • Пропускная способность релиза: успешные загрузки TestFlight в фиксированном 4-часовом окне
  • Пассивное ожидание: опрос «сколько ждали CI сегодня» или метки времени в PR

Экспорт: GitHub API run_started_at минус created_at; или шаг workflow, пишущий секунды очереди в artifact. Без baseline ROI руководству доказать сложно.

МетрикаКак собиратьСигнал успеха после миграции
Queue P95Actions API / свой stepс >20 мин до <3 мин
PR feedback P50Метки времени PRснижение >50%
Hit rate кэшаРазмер DerivedData + лог сборкис <20% до >60%
Частота сбоев при параллелизмеДоля падений при нескольких job на одной машинепосле изоляции каталогов <2%

Три команды: до и после миграции

Все три набора — реальные проекты (анонимно), тот же репозиторий, та же мажорная версия Xcode, две недели будних дней.

Кейс A: iOS-команда 12 человек, одно приложение + extensions

До: всё на macos-14; после: 2× M4 16 ГБ Cloud Mac как self-hosted runner, DerivedData на локальном NVMe. ~18 PR/день.

МетрикаДоПослеИзменение
PR feedback P5052 мин11 мин−79%
Queue P9538 мин0,8 мин−98%
Archive разово12,4 мин9,1 мин−27%
TestFlight/ночь1,54+167%

Tech Lead дословно: «Раньше push в пять — merge только в пол-седьмого; сейчас наливаю воду — PR уже зелёный».

Кейс B: 28 человек, KMP + Android-основной репо, Mac только для iOS-оболочки

До: macOS- и Android-job в одном релизном окне; после: 1× постоянный M4 Pro + 2 burst Cloud Mac в релизную неделю (см. playbook burst-релизов).

МетрикаДоПослеИзменение
Dual-platform PR зелёный P5071 мин24 мин−66%
Суммарная queue/день в релизную неделю6,2 ч0,4 ч−94%
Ожидание/нед (опрос)4,8 чел·ч1,1 чел·ч−77%

Кейс C: indie 8 человек, 2 релиза в месяц

Контрпример: почти без выигрыша — мало PR, очереди нет, зато обслуживание keychain на своей машине. Archive лишь 10,2 → 9,4 мин (−8%), queue и так ~0. «Насколько» сильно зависит от профиля нагрузки.

Как читать таблицы: в A/B около 60–75% — исчезновение очереди, 15–25% — персистентный DerivedData / SwiftPM, остальное — параллельные машины. Только смена runner без кэша режет выигрыш пополам.

Откуда рост: очередь, кэш, параллелизм

Разбейте общее ожидание — так проще объяснить нетехническим stakeholders:

PR total ≈ очередь + подготовка среды + сборка/тесты + upload

1. Очередь (самый большой блок): macOS pool GitHub общий; в релизную или Xcode-upgrade неделю P95 30+ мин — норма. Свой узел = выделенный executor, queue почти исчезает.

2. Cold start и кэш: hosted job уничтожается — DerivedData, Pods, SwiftPM каждый раз заново. Персистентные тома на своих машинах: вторая сборка часто ~20% быстрее; подробнее в FAQ по кэшу и диску self-hosted runner.

3. Параллелизм: 2–3 Mac на matrix-job — релизная ночь не «вереница». На одном хосте — изоляция каталогов, иначе flakiness съест выигрыш.

ФазаHosted runner типичноПосле своих узлов
Очередь45–70%<5%
Распаковка deps / индекс15–25%5–10% (персистентный кэш)
Чистая сборка/тесты20–35%15–30%

Двухнедельный путь: сначала сравнение, потом трафик

Переключать прод в пятницу вечером — плохая идея. Воспроизводимый ритм:

  • Дни 1–2: экспорт двух недель queue/duration из Actions; 1× Cloud Mac (~5 мин), runner, runs-on: [self-hosted, macos, canary] только вручную
  • Дни 3–5: персистентные ~/ci/DerivedData и SwiftPM; один и тот же commit main — A/B по 5 раз, P50
  • Дни 6–8: release/nightly 50% на self-hosted label; hosted как fallback
  • Дни 9–10: все PR required checks на self-hosted; порог диска 80% и cron очистки артефактов
  • Дни 11–14: сводная таблица, ROI для руководства; решение: 1 постоянная машина или burst по дням

Оркестрация остаётся в GitHub Actions — YAML, permissions, environment protection без смены платформы, меняется только runs-on. Та же логика, что в корпоративном Mac CI pool: разделить оркестрацию и исполнение.

Минимальное изменение workflow

jobs:
  ios-build:
    # До: runs-on: macos-14
  ios-build:
    runs-on: [self-hosted, macos, ios-pool]
    steps:
      - uses: actions/checkout@v4
      - name: Log queue metrics
        run: echo "QUEUE_SEC=${QUEUE_SEC:-0}" >> $GITHUB_STEP_SUMMARY

Ещё не решили про железо? Аренда M4 Cloud Mac по дням на две недели сравнения — часто дешевле, чем час простоя всей команды.

Грубый ROI: перекрывает ли эффективность стоимость машин?

На примере кейса A (ставка blended $55, иллюстрация):

  • 12 человек × 3,7 ч меньше ожидания/нед ≈ 44 чел·ч/мес$2 420/мес эквивалентного output
  • 2× M4 16 ГБ Cloud Mac ≈ $206/мес ($103×2, по странице тарифов)
  • Ops платформы ≈ 4–8 чел·ч/мес (диск, сертификаты, upgrade runner)

Чистый результат часто положительный — у малых команд с редкими сборками (кейс C) может не сойтись. Подставьте свой queue P95:

выигрыш/мес ≈ разработчики × меньше ч ожидания/нед × 4 × ставка − аренда − ops ч × ставка

В релизную неделю — третья машина burst, в спад — отказ. Долгий TCO покупка vs аренда: купить Mac mini или арендовать Cloud Mac.

Когда лучше не мигрировать

В этих случаях советую подождать или арендовать на неделю для проверки:

  • <30 macOS job/мес и queue P95 стабильно <5 мин — потолок низкий (кейс C)
  • Некому on-call обслуживать runner — полный диск хуже очереди
  • Compliance: машина только в своей VPC — сначала сеть и secrets
  • Ожидание «без GitHub Actions» — оркестрация, audit, permissions всё ещё ценны

Миграция — средство; цель — измеримо меньше ожидания. Если за две недели сравнения нет >30% улучшения PR-цикла — сначала оптимизируйте workflow (split job, реже archive), а не покупайте три Mac.

FAQ

Насколько обычно растёт эффективность?

У частых iOS-сборок часто ~70% короче PR-цикл и очередь почти ноль; чистая компиляция +15–25%. Редкие сборки — часто однозначные проценты; сначала baseline.

Хватит ли одного Mac?

Для <10 человек и серийных релизов обычно да; при matrix или нескольких app — от 2, с лимитом concurrency против конфликтов кэша.

Уменьшится ли счёт Actions?

macOS-минуты часто −60–90% (сколько job перенесли); растут аренда и ops. Смотреть суммарно с ROI выше.

Cloud Mac vs офисный Mac mini?

Один chip/RAM — близкое время сборки. Разница: RTT (deps, upload) и NVMe. Узел ближе к хостингу кода и registry артефактов.

Подпись и notarization?

Сами по себе не улучшаются — но стабильная среда снижает drift keychain/provisioning и «только в CI» ночные пожары.

Когда виден эффект?

Runner + каталог кэша: первый рабочий день в метриках queue; PR-цикл — две недели измерений перед отчётом.

Итог и дальнейшее чтение

Миграция с GitHub Actions на собственные Mac-узлы: ответ не «намного быстрее». Типичные iOS-команды видят ~70% короче PR и ~2× пропускную способность релиза — главная доля исчезновение очереди, затем персистентный кэш. Двухнедельное сравнение, четыре метрики и ROI дают цифры для руководства; без явного эффекта сначала workflow, не железо.