Neuspjelo ponovno objavljivanje nikad ne briše radni backend
Dana 25. rujna neuspjelo ponovno objavljivanje izbrisalo je backend jedne aplikacije koji je radio i bio uživo oko dva i pol sata. Kod koji poništava neuspjelu objavu uklonio je svaku serversku aplikaciju koju je objava dotaknula, uključujući one koje su već služile prije nego je objava počela. Sada se brišu samo aplikacije koje je objava stvorila, a postojeća aplikacija vraća se na točno onu verziju koju je imala prije. Dva naknadna ispravka istog dana osigurala su da se poništavanje pokrene i kad alat hosting platforme za deploy sam zakaže, te da zdrava aplikacija ne bude označena kao neuspješna samo zato što je spavala.
Kako se backend objavljuje
Kad vaša Mythex aplikacija ima backend, odnosno API ili server, a ne samo statične datoteke, objava ga gradi iz Dockerfilea (recepta za pakiranje aplikacije u sliku) i postavlja tu sliku na strojeve naše hosting platforme. Zatim provjera zdravlja čeka da se nova verzija zaista pokrene i ostane pokrenuta, tek tada se objava označava kao aktivna.
Ako nešto pođe po zlu usput, pokreće se vraćanje (rollback) koje to poništava. Ispravno vraćanje važno je gotovo više od bilo čega drugog u objavljivanju, jer se pokreće upravo kad nešto već ide po zlu.
Problem 1: vraćanje je obrisalo ono što je trebalo vratiti
Vraćanje je vodilo popis serverskih aplikacija na koje je objava postavljena i u slučaju neuspjeha uništilo ih je sve. To je ispravno za prvu objavu: aplikacija je tek stvorena, ništa o njoj ne ovisi, a brisanje ostavlja stanje onakvim kakvo je bilo.
Za ponovno objavljivanje to je potpuno pogrešno. Aplikacija je već postojala i služila je pravim posjetiteljima. Dana 25. rujna API aplikacije koji je bio uživo dva i pol sata obrisala je neuspjela ponovna objava.
U istom kodu krio se i drugi kvar. Ako brisanje nije uspjelo, pokvarena nova slika ostajala je na strojevima, dok smo vlasniku ipak javljali da je njegova trenutna stranica i dalje aktivna. Kad provjera zdravlja može zakazati, nova slika je već postavljena na sve strojeve. Ne raditi ništa nije isto što i poništiti.
Ispravak: obriši samo ono što si stvorio, vrati ostalo
Svaka objava sada za svaku serversku aplikaciju koju dotakne bilježi:
- je li je ova objava stvorila, i
- ako nije, koju je sliku pokretala neposredno prije.
Pri neuspjehu svaka aplikacija dobiva jedan od tri postupka:
- Stvorila ju je ova objava: obriši je, kao i prije.
- Već je postojala, prethodna slika poznata: ponovno postavi prethodnu sliku s istom konfiguracijom. Nema izgradnje, samo se slika vraća.
- Već je postojala, prethodna slika nepoznata: ne diraj je. Postojeća aplikacija nikad se ne briše, čak ni kad je ne možemo vratiti.
Ta pravila su mala čista funkcija s vlastitim testovima, pa se odluka ne može vratiti na “obriši sve” a da test ne pukne.
Problem 2: alat za deploy mogao je zakazati prije nego smo zapisali kako poništiti
Ubrzo nakon tog ispravka pronašli smo rupu u njemu. Alat hosting platforme za deploy sam pokreće vlastite provjere: ako se novi strojevi sruše, izlazi s greškom. Ali to radi nakon što je nova slika već na strojevima.
Naš kod aplikaciju je registrirao za vraćanje tek kad je alat uspješno završio. Kad je sam alat prekinuo deploy, aplikacija nije bila na popisu za vraćanje, pa se ništa nije vratilo. Na našem staging okruženju neuspjela ponovna objava ostavila je pokvarenu sliku u funkciji.
Ispravak: registriraj poništavanje prije početka
Aplikacija se sada registrira za vraćanje, uz to je li stvorena i koju je sliku pokretala, čim se pripremi, a prije nego se išta postavi na nju. Što god se kasnije dogodi, vraćanje zna što treba vratiti. Provjerili smo lokalno: neuspjela ponovna objava pala je na vlastitim provjerama alata za deploy, a prethodna verzija nastavila je odgovarati.
Problem 3: spavajuća aplikacija označena je kao “nikad nije pokrenuta”
Objavljene aplikacije na Mythexu spavaju kad su neaktivne kako bi uštedjele vaše kredite. Ponovna objava ostavlja spavajući stroj zaustavljenim, pa provjera zdravlja mora ga probuditi. Ona je platformu pitala da pokrene stroj jednom i ignorirala odgovor.
Dana 25. rujna taj jedini zahtjev za pokretanje nije stigao nikamo. Zdrav API stajao je zaustavljen cijelih pet minuta provjere zdravlja i bio je označen kao neuspješan s porukom “1 stroj nikad nije pokrenut (zadnje stanje: zaustavljen)”.
Platforma ponekad odbije pokretanje. Dok smo ovo reproducirali, bez ikakvog našeg poticanja vratila je konflikt “lease currently held”, a odbija pokretanja i dok se stroj ažurira.
Ispravak: pitaj ponovno i pokucaj na vrata
Provjera zdravlja sada:
- ponovno traži pokretanje zaustavljenog stroja svakih 20 sekundi dok čeka,
- bilježi što je platforma odgovorila kad odbije, i
- šalje jedan obični zahtjev aplikaciji, baš kao posjetitelj, jer proxy platforme probudi spavajući stroj čim stigne zahtjev.
Reproducirali smo to na pravoj platformi s jednokratnom aplikacijom čije je prvo pokretanje bilo odbijeno. Prije ispravka objava je pala nakon 91 sekunde. Nakon ispravka objavljena je za 20 sekundi. Aplikacija koja se doista ruši pri pokretanju i dalje pada, kako i treba.
Što smo iz ovoga naučili
- Vraćanje mora znati razliku između novog i postojećeg. “Poništi” za nešto što si stvorio znači obriši. “Poništi” za nešto što je već bilo znači vrati. Kad se oba tretiraju isto, sigurnosni mehanizam obriše radnu aplikaciju.
- Zapiši kako poništiti prije nego što djeluješ. Ako se poništavanje bilježi tek nakon što korak uspije, korak koji pukne na pola puta ne ostavlja ništa čime bi se moglo poništiti.
- Nikad ne ignoriraj odgovor na zahtjev o kojem ovisiš. Jedno ignorirano “ne” pretvorilo je zdravu aplikaciju u neuspjelu objavu.
Povezani ispravak istog dana: kako uhvatiti aplikacije koje se sruše odmah nakon objave. Što se događa kad objava pukne na našoj strani, pogledajte rješavanje problema pri objavi u dokumentaciji.