Индекс на дневникаDockup / бележка от практиката
Note / deployment-stuck-in-queued

Deployment, заседнал в опашката: какво да проверите първо

Deployment, заседнал в опашката, обикновено чака нещо извън вашия build. Научете какво означава queueing, как да различите изчакване от блокиране и как да задвижите заседнал release.

Deployment, заседнал в queued, е един от най-малко информативните проблеми, които една платформа може да ви покаже. Нищо не е сринато. Няма логове, защото нищо не е стартирало. Release-ът просто стои там и при всяко презареждане виждате същата дума.

Най-дразнещото е, че „queued“ обхваща поне четири различни ситуации, които нямат нищо общо помежду си. Да разберете в коя от тях се намирате, отнема около тридесет секунди и определя дали трябва да изчакате, да направите retry или да потърсите причината някъде съвсем другаде.

Какво всъщност означава „queued“

Queued deployment е приет и записан, но все още не му е назначен worker. Между тези два момента трябва да са изпълнени няколко условия:

  • Платформата трябва да изтегли source кода ви, което обикновено означава API call към вашия Git provider.
  • Трябва да има свободен build slot.
  • Всеки prerequisite в release-а трябва да е приключил — migration стъпка, volume операция или по-ранен deployment на същия service.

Ако някое от тези неща е блокирано, записът съществува, но работата не започва. Това е целият механизъм. Не е мистерия, но повечето dashboard-и визуализират и четирите случая с една и съща дума.

Четирите случая в реда, в който е най-разумно да ги проверите

1. Вашият Git provider има проблеми

Това е най-честата причина и тази, по която не можете да направите нищо. Платформата е поискала repository-то ви и е получила бавен отговор или грешка. Ако няколко несвързани service-а влязат в queue по едно и също време и нямат общ код, shared dependency-то е provider-ът.

Проверете status page-а на provider-а си преди всичко останало. Deploy, който чака upstream API, ще се изчисти сам, а retry-ването само добавя още един запис към купчината — затова заседналата queue толкова често се превръща в пет заседнали queue-и.

2. Нещо преди него още не е приключило

Повечето платформи сериализират deployment-ите за всеки service, и с основание: два build-а, които записват един и същ image tag, не са race condition, която искате да спечелите. Ако по-ранен deployment на този service все още се изпълнява — или, още по-лошо, системата все още смята, че се изпълнява, защото worker-ът е прекъснал работа, без да докладва — следващият изчаква.

В Dockup dockup deployments показва историята, започвайки с най-скорошния запис, заедно със status-а на всеки от тях. Ако записът над вашия queued release не е в terminal state, това е отговорът ви, а cancel-ването му или изчакването да изтече timeout-ът е това, което освобождава опашката.

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

Изходът с --json включва status-а и duration-а на всеки deployment, което прави очевидно, че „предишният така и не е приключил“ — по начин, по който един spinner не може.

3. Няма capacity

Всяка платформа разполага с краен брой build worker-и. При shared tier внезапен пик на активността в платформата може да ви постави зад build-овете на други потребители. Това е реална ситуация, обикновено е краткотрайна и е единственият случай, в който изчакването наистина е правилното действие.

Важно е дали можете да го видите. Позиция в queue или приблизително време за изчакване превръщат изживяването, наподобяващо outage, в нормална ситуация. Самото „queued“ не го прави.

4. Deployment-ът изобщо няма да стартира

Неприятният случай: записът е създаден, но нещото, което е трябвало да го поеме, така и не го е направило. Worker е crash-нал, webhook е изгубен или token е изтекъл между trigger-а и fetch-а.

Показателно е времето. Изчакването в queue обикновено се измерва в секунди до няколко минути. Deployment, който е queued от десет минути без друг release преди него, не изчаква — той е заседнал и ще си остане такъв.

Как да различите изчакване от блокиране

Преди да направите retry, съберете три факта:

  1. Изпълнява ли се друг deployment? Ако друг release на същия service се изпълнява, това е случай 2 и трябва да го оставите да приключи.
  2. Колко време е queued? Под две минути е нормално. Над десет — не.
  3. Влязоха ли други service-и в queue по същото време? Ако несвързани service-и са спрели едновременно, потърсете причината upstream, а не в кода си.

Тези три отговора почти винаги разделят „изчакай“ от „действай“.

Защо retry обикновено влошава проблема

Инстинктивната реакция при заседнал release е отново да натиснете deploy. При сериализиран pipeline това е контрапродуктивно: добавяте втори запис зад първия, а ако първият наистина е заседнал, вторият наследява блокирането. Разработчиците, които попаднат в тази ситуация, често накрая получават колона от queued записи, нито един от които няма да се изпълни, докато началото на опашката не се освободи.

Ако ще правите retry, първо cancel-нете заседналия deployment. Един queued deployment, който видимо се провали, е много по-полезен от пет, които просто стоят.

Как решаваме този проблем в Dockup

Важното дизайнерско решение тук е, че deployment никога не остава в състояние, в което системата смята, че се изпълнява. Всеки deployment има terminal state и достигането му освобождава опашката. Build, който прекъсне работа, без да докладва, също изтича по timeout и освобождава service-а.

Още две неща помагат повече, отколкото изглежда:

Етапите са именувани. Deployment-ът в Dockup преминава през извличане на source кода, build и health gate, като всеки етап записва собствената си duration. Когато нещо е бавно, виждате кое точно е бавно, вместо да наблюдавате една дума. stageTimings присъства във всеки deployment record, включително при използване на --json.

След вече провалил се release не се натрупват queued deployment-и. Ако health check-ът никога не мине, deployment-ът приключва — той не заема service-а, докато се чудите какво се случва. Предишната версия продължава да обслужва трафика през цялото време, което е и другата причина заседналият release да не води до outage в Dockup.

# 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

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

Queueing не е failure mode. Queueing без посочена причина е. Всяка платформа понякога ще ви накара да изчакате Git provider или build slot; разликата между петминутно раздразнение и изгубен следобед е дали интерфейсът ви показва в кой от четирите случая се намирате.

Когато преценявате къде да стартирате нещо, струва си умишлено да проверите това: задействайте deploy и вижте какво показва платформата между приемането му и стартирането. Ако отговорът е една-единствена дума без timestamp, рано или късно ще изгубите цял следобед заради това.

Често задавани въпроси

Колко време трябва да остане deployment-ът queued? Секунди до няколко минути при изправна платформа. Всичко над десет минути, когато пред него няма нищо, трябва да се счита за заседнало, а не просто за бавно.

Трябва ли да направя retry на queued deployment? Не и преди да го cancel-нете. При сериализиран pipeline retry-ят се нарежда зад заседналия deployment и наследява същото блокиране.

Може ли заседнал deployment да спре сайта ми? Не би трябвало. При платформа, която пренасочва трафика едва след като новият release премине health check-а, работещата версия продължава да обслужва трафика през цялото време — queued или failed deploy е release, който така и не се е случил, а не outage.

Защо няколко service-а влизат в queue едновременно? Защото споделят dependency и почти винаги причината е Git provider-ът или build fleet-ът, а не нещо в кода ви.