Индекс журналаDockup / заметка с места
Note / deployment-stuck-in-queued

Деплой застрял в очереди: что проверить в первую очередь

Если деплой застрял в очереди, обычно он ждёт чего-то за пределами вашего build-процесса. Узнайте, что означает постановка в очередь, как отличить ожидание от зависания и как сдвинуть застрявший релиз с места.

Деплой, застрявший в очереди, — один из наименее информативных сбоев, с которыми может столкнуться платформа. Ничего не упало. Логи не появились, потому что ничего не запустилось. Релиз просто стоит на месте, и после каждого обновления страницы вы видите одно и то же слово.

Самое неприятное в том, что за статусом «в очереди» скрываются как минимум четыре разные ситуации, не связанные между собой. Определить, с какой из них вы столкнулись, можно примерно за тридцать секунд — и это подскажет, нужно ли ждать, повторить попытку или искать причину совсем в другом месте.

Что на самом деле означает статус «в очереди»

Деплой в очереди принят и зарегистрирован, но ему ещё не назначен worker. Между этими двумя моментами должно произойти несколько вещей:

  • Платформа должна получить исходный код — обычно для этого выполняется API-вызов к вашему Git-провайдеру.
  • Должен освободиться слот для сборки.
  • Все предварительные этапы релиза должны завершиться — шаг миграции, операция с volume или предыдущий деплой того же сервиса.

Если что-то из этого заблокировано, запись существует, но работа не начинается. Вот и весь механизм. Никакой загадки здесь нет, однако большинство dashboard отображают все четыре случая одним и тем же словом.

Четыре случая — проверяйте именно в таком порядке

1. У вашего Git-провайдера проблемы

Это самая распространённая причина, на которую вы не можете повлиять. Платформа запросила ваш repository и получила медленный ответ или ошибку. Если несколько несвязанных сервисов одновременно встали в очередь и у них нет общего кода, значит, общая зависимость — это провайдер.

Прежде всего проверьте status page провайдера. Деплой, ожидающий ответа от upstream API, завершит ожидание сам, а повторная попытка лишь добавит ещё одну запись в очередь — поэтому одна застрявшая очередь так часто превращается в пять.

2. Что-то перед ним ещё не завершилось

Большинство платформ последовательно выполняют деплои одного сервиса, и это правильно: два build-процесса, записывающих один и тот же image tag, — это race condition, которую вам не захочется выигрывать. Если предыдущий деплой этого сервиса всё ещё выполняется — или, что ещё хуже, считается выполняющимся, потому что worker завершился без отправки статуса, — следующий будет ждать.

В Dockup команда dockup deployments выводит историю начиная с самого последнего деплоя и показывает статус каждой записи. Если деплой непосредственно перед вашим релизом в очереди не находится в terminal state, причина найдена: отмените его или дождитесь тайм-аута, чтобы разблокировать очередь.

dockup deployments my-project/my-api --json

В выводе --json для каждого деплоя указаны статус и длительность, поэтому становится очевидно, что «предыдущий так и не завершился», — гораздо очевиднее, чем по одному spinner.

3. Нет свободных ресурсов

На каждой платформе конечное число build worker. На shared tier всплеск активности во всей платформе может поставить вашу сборку после сборок других пользователей. Это реальная, обычно кратковременная ситуация — и единственный случай, когда ждать действительно правильно.

Здесь важно, можете ли вы это увидеть. Позиция в очереди или приблизительная оценка времени ожидания превращают ситуацию, похожую на outage, в обычное ожидание. Простого статуса «в очереди» недостаточно.

4. Деплой вообще не должен был запуститься

Самый неприятный вариант: запись создана, но механизм, который должен был её обработать, так и не сработал. Worker упал, webhook потерялся, token истёк между запуском и получением исходного кода.

Главный признак — время. Ожидание в очереди обычно занимает от нескольких секунд до пары минут. Если деплой находится в очереди десять минут, а перед ним нет других релизов, он не ждёт — он завис и, скорее всего, так и останется зависшим.

Как отличить ожидание от зависания

Перед повторной попыткой выясните три факта:

  1. Выполняется ли сейчас что-нибудь ещё? Если выполняется другой релиз того же сервиса, это случай 2 — оставьте его в покое.
  2. Как долго деплой находится в очереди? Менее двух минут — нормально. Больше десяти — уже нет.
  3. Встали ли другие сервисы в очередь одновременно? Если все несвязанные сервисы остановились в один момент, ищите причину upstream, а не в своём коде.

Эти три ответа почти всегда позволяют отличить ситуацию «ждать» от ситуации «действовать».

Почему повторная попытка обычно всё усугубляет

Первая реакция на застрявший релиз — снова нажать кнопку deploy. В pipeline с последовательным выполнением это контрпродуктивно: вы добавляете вторую запись за первой, а если первая действительно зависла, вторая тоже унаследует блокировку. Разработчики, столкнувшиеся с этим, часто получают целый столбец записей в очереди — ни одна из них не запустится, пока не освободится начало очереди.

Если собираетесь повторить попытку, сначала отмените застрявший деплой. Один деплой в очереди, который явно завершился ошибкой, гораздо полезнее пяти деплоев, просто стоящих на месте.

Как это устроено в Dockup

Ключевое архитектурное решение здесь заключается в том, что деплой никогда не считается выполняющимся бесконечно. У каждого деплоя есть terminal state, и именно переход в него освобождает очередь. Даже если build-процесс завершился без отправки статуса, по тайм-ауту он всё равно освобождает сервис.

Есть ещё две вещи, которые помогают сильнее, чем может показаться:

У этапов есть названия. Деплой в Dockup проходит через получение исходного кода, сборку и health gate, а для каждого этапа отдельно сохраняется длительность. Если что-то выполняется медленно, вы видите, что именно тормозит, а не просто наблюдаете одно слово. stageTimings есть в каждой записи о деплое, в том числе при использовании --json.

За завершившимся ошибкой релизом ничего не стоит в очереди. Если health check не проходит, деплой завершается — он не продолжает занимать сервис, пока вы гадаете, что происходит. Предыдущая версия всё это время продолжает обслуживать traffic, и это вторая причина, почему застрявший релиз в Dockup не превращается в outage.

# What is the current state, and how long has each stage taken?
dockup status my-project/my-api --json

# Follow the build as it happens rather than waiting for a summary
dockup logs my-project/my-api --build --follow

Общее правило

Постановка в очередь сама по себе не является сбоем. Сбоем является постановка в очередь без объяснения причины. Любая платформа время от времени заставляет вас ждать Git-провайдера или свободный build slot; разница между пятиминутным неудобством и потерянным днём заключается в том, сообщает ли интерфейс, с каким из четырёх случаев вы столкнулись.

Когда вы выбираете, где запускать сервис, это стоит проверить специально: запустите деплой и посмотрите, что платформа показывает в промежутке между его принятием и началом выполнения. Если ответ — одно слово без timestamp, однажды вы обязательно потратите на это целый день.

Часто задаваемые вопросы

Как долго деплой может находиться в очереди? От нескольких секунд до пары минут на исправной платформе. Если прошло больше десяти минут и перед ним ничего нет, считайте его застрявшим, а не просто медленным.

Стоит ли повторять попытку для деплоя в очереди? Не отменив его предварительно — нет. В pipeline с последовательным выполнением повторная попытка встанет за застрявшим деплоем и унаследует ту же блокировку.

Может ли застрявший деплой положить мой сайт? Не должен. На платформе, которая переключает traffic только после прохождения health check новым релизом, работающая версия продолжает обслуживать запросы всё это время — деплой в очереди или завершившийся ошибкой означает, что релиз не состоялся, а не что произошёл outage.

Почему несколько сервисов одновременно встают в очередь? Потому что у них есть общая зависимость — почти всегда это Git-провайдер или build fleet, а не что-то в вашем коде.