VPSSpark Блог
← К дневнику

Почему macOS job в GitHub Actions долго в Queued (это не медленный Xcode)

Заметки с сервера · Cloud Mac CI #2 · 2026.06.05 · ~14 мин

Запросы: GitHub Actions macOS runner queued · macos runner stuck in queued · CI queue wait time high · self-hosted runner not starting

Очередь GitHub Actions macOS runner, статус Queued
При macOS runner queued сначала смотрите wait time.

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.

52 min
ожидание
11 min
выполнение
Queued
≠ In progress
ожидание выполнение
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 рекомендации. Нарушение = инцидент.

CI Hard Rules
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-fast
                main   → 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

PR запускает 6 macOS jobmatrix не урезана
L2 Archive 38 мин на одном runner
L0/L1 все Queuedself-hosted runner queue заблокирована
Пример workflow (без L2 на PR)
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)

CI Queue Diagnosis · Standard Path
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.

Серия (#2 диагностика очереди)
#1 ёмкость · #2 эта страница · #3 TCO self-hosted · #4 Xcode Cloud · #5 кейс 20 человек · #6 изоляция Archive · #7 выбор платформы · #8 скорость

Проверить 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.

Акция

macOS runner queued? Сначала wait time

GitHub Actions macOS runner queue

На главную
Акция Смотреть тарифы