VPSSpark стандарт диагностики CI-очереди (Cloud Mac CI #2). Порядок: Hook → формула → симптомы → Failure Model → Hard Rules → Runbook → FAQ. Связанное: #1 ёмкость · #5 кейс масштабирования · #3 TCO self-hosted · #8 скорость сборки.
1 · Hook: неочевидный вывод
В большинстве инцидентов macOS CI со статусом queued дело не в «не хватает Mac»—на пути PR крутится L2 (Archive). На практике это девять из десяти тикетов.
В Slack быстро пишут «CI тормозит». В GitHub Actions Queued и In progress—разные метрики. Без вопроса «ожидание сильно больше выполнения?» уходят в апгрейд Xcode или покупку минут—очередь runner’ов от этого не исчезает. Эта статья—норма для такого разделения.
2 · Ядро: одна формула
Всё ниже разворачивает эту проверку. Вставьте в on-call wiki как есть.
Главная формула
CI queue problem ⇔ wait time >> run time
Инженерное чтение: macOS runner queued означает насыщение пула runner’ов, а не медленный Xcode.
Формула ложна → не эта статья; см. #8 (Xcode/кэш). Истина → Failure 3 Layer Model и CI Hard Rules.
Частый паттерн: смешивают hosted macos-latest и self-hosted и видят «минуты есть, а Queued». Путают minutes (биллинг) и concurrency (одновременные слоты). Пул и триггеры трогайте только при истинной формуле.
3 · Симптом: Queued ≠ Running
В GitHub Actions Queued—джоб в workflow, но слота runner’а ещё нет. В In progress идут checkout, xcodebuild, подпись. Красный PR на час называют «медленной сборкой»—в timeline типично 52 минуты ожидания, 11 минут работы.
Типичные ложные фиксы: поднять Xcode, увеличить timeout-minutes, купить минуты GitHub. Время Queued часто не входит в тот timeout, который вы думаете настроили.
Мерить через время выполнения job (queue_wait_seconds vs длительность run). Недельный P95 ловит Trigger Explosion до пятничного merge-rush.
| ожидание | выполнение | |
|---|---|---|
| UI | Queued | In progress |
| Узкое место | GitHub Actions macOS runner queue / self-hosted runner queue | Xcode · подпись · upload |
| Неверный фикс | больше минут · новый Xcode | кэш (→ #8) |
Когда в чате винят DerivedData, а badge долго в Queued, смотрят не туда. В runbook логируйте ожидание и выполнение раздельно—иначе снова купят не тот рычаг.
4 · Объяснение: CI Queue Failure 3 Layer Model
При wait time >> run time причина в одном из SRE-слоёв (или в их стеке).
| Слой | Смысл | Сигналы | Сегодня |
|---|---|---|---|
| Capacity Limit | Платформа · macos-latest |
Только hosted macOS runner queued; minutes ≠ concurrency | Урезать fanout; Archive с hosted → #3 |
| Pool Misdesign | Архитектура · self-hosted | Archive на PR; fast/archive вместе; один runner блокирует всех | Hard Rules → #1 #6 |
| Trigger Explosion | Нагрузка · fanout workflow | matrix / paths / дубли workflow; jobs > runners | Ужать триггеры → #5 |
Capacity Limit — упирается в hosted macOS runners и лимит concurrency macOS организации (limits). Pool Misdesign — частый корень: L2 на PR, смешанные пулы. Trigger Explosion — чинить YAML, не железо. (Слои Failure ≠ тиры L0/L1/L2.)
Слои не взаимоисключают: в пятницу вечером растёт matrix (Trigger), Archive держит fast (Pool), hosted-квота пуста (Capacity)—«тройка» из кейса на 20 человек #5 повторяется часто. Начинайте с колонки «Сигналы».
5 · Исправление: CI Hard Rules (MUST NOT нарушать)
Нормативный язык для runbook—not рекомендации. Нарушение = инцидент.
Rule 1: PR MUST NOT run L2 Rule 2: L2 MUST run on isolated pool (macos-archive) Rule 3: fast pool MUST remain unblocked (fast ≠ archive) # Mapping PR → L0 + L1 only →macos-fastmain → L2 only →macos-archive
Справка по тирам job (только реализация Hard Rules):
| Tier | Работа | Пул | Правила |
|---|---|---|---|
| L0 | Сборка модулей, lint, лёгкие тесты | macos-fast |
Rule 1 · OK на PR |
| L1 | Интеграция PR, тесты на симуляторе | macos-fast |
Rule 1 · MUST NOT Archive |
| L2 | Archive, IPA, TestFlight | macos-archive |
Rules 2+3 · PR MUST NOT |
«Один раз Archive на PR» кажется мелочью—38 минут L2 на одном label держат все L0/L1 в Queued. Исключения ломают пул; release — на main / schedule.
Рис. 1 · Pool Misdesign: L2 держит слот → все macOS job в queued
jobs: pr-fast: if: github.event_name == 'pull_request' runs-on: [self-hosted, macos-fast] release-archive: if: github.ref == 'refs/heads/main' || github.event_name == 'schedule' runs-on: [self-hosted, macos-archive]
Топология runner’ов: elastic vs always-on · #1 sizing · после здоровой очереди → #3.
6 · Runbook: одна страница (on-call)
0. CI queue problem ⇔ wait time >> run time ? ─No→ #8
1. Layer: Capacity | Pool Misdesign | Trigger Explosion
2. MUST: Rule1 PR no L2 · Rule2 L2 isolated · Rule3 fast unblocked
3. PR workflow has no archive/export/upload ?
4. wait P95 < 8min → then size runners (#3)
Одной строкой: Большинство queued в macOS CI — это L2 на пути PR, а не нехватка железа. macOS runner queued = насыщение пула; wait >> run, затем Failure Model, затем Hard Rules.
В postmortem «купили runner’ов» без Rule 1–3 в репо инцидент повторится. Чекбокс в PR «нет Archive-job» заметно снижает рецидив.
7 · FAQ
Почему macOS runner’ы чаще в очереди?
Capacity Limit (лимит concurrency) плюс Pool Misdesign (L2 на PR). Начните с wait >> run.
Очередь или медленная сборка?
CI queue problem ⇔ wait time >> run time. Истина → пул; ложь → #8.
Почему queued при self-hosted?
Pool Misdesign: self-hosted runner queue следует вашим labels и раскладке пулов. Нарушение Hard Rules блокирует очередь—облачный Mac не чинит плохой YAML.
Минуты GitHub Actions vs concurrency?
minutes — биллинг; concurrency — одновременные слоты. Больше минут не снимает macOS runner queued.
Это проблема пула runner’ов?
wait >> run + один self-hosted долго занят → Pool Misdesign; только macos-latest queued → Capacity Limit. См. Runbook.
Очередь OK, сборка всё ещё медленная?
#8 (скорость). Sizing: #1. Рост команды: #5.
Проверить split пулов: нужен PoC fast pool?
После Hard Rules, чтобы вынести L0/L1 из hosted GitHub Actions macOS runner queue, поднимите один runner macos-fast и убедитесь, что wait time P95 < 8 мин—затем добавьте macos-archive по #1.
Для ежедневного изолированного fast pool без переделки офисной сети: тарифы Mac cloud или главная VPSSpark—только валидация топологии; правила обязательны. TCO: серия #3.