Wykrywanie aplikacji, które padają tuż po publikacji
25 września trzy publikacje zostały oznaczone jako udane, mimo że API aplikacji padało sekundy po każdym uruchomieniu. Ponieważ publikacje „się udały”, wycofanie nie uruchomiło się. Kilka minut później kontrola w tle oznaczyła wdrożenia jako błędne i cała strona przeszła w 404. Kontrola stanu liczyła awarie w liście zdarzeń platformy hostingowej, która przechowuje tylko ostatnich pięć zdarzeń na maszynę. Pętla awarii wypełnia ją, więc liczba nigdy nie rośnie. Teraz kontrola porównuje czas najnowszej awarii, a publikacja z pętlą awarii kończy się błędem i przywraca poprzednią wersję.
Na co czeka publikacja
Gdy publikujesz aplikację z backendem w Mythex, nowa wersja jest wdrażana na maszyny naszej platformy hostingowej, a kontrola stanu decyduje, czy publikacja weszła na żywo, czy się nie powiodła. Jeśli się nie powiodła, wycofanie przywraca poprzednią wersję.
Trudność polega na tym, że „uruchomiona” nie znaczy „obsługuje ruch”. Platforma zgłasza maszynę jako uruchomioną, gdy tylko wstanie. Aplikacja, która pada sekundę po starcie, zostaje natychmiast uruchomiona ponownie i chwilę później znowu wygląda na uruchomioną. Kontrola stanu z czasem obrosła w kilka warstw:
- Spójrz dwa razy. Gdy maszyna zgłasza się jako uruchomiona, poczekaj chwilę i spójrz ponownie. Awaria przy starcie często wychodzi przy drugim spojrzeniu.
- Szukaj pętli awarii. Jeśli platforma zgłasza, że maszyna wielokrotnie padała i przestała ją restartować, zakończ błędem.
- Licz awarie od początku publikacji. Dwa spojrzenia na „uruchomioną” mogą obejmować restart. Więc jeśli od początku tej publikacji zdarzyła się jakakolwiek awaria, spójrz jeszcze raz; jeśli awarii jest więcej niż przy poprzednim spojrzeniu, aplikacja nie utrzymuje się w działaniu.
Trzecia kontrola to ta, która tutaj zawiodła.
Dlaczego liczba stała w miejscu
Informacje o awariach pochodzą z listy zdarzeń każdej maszyny: uruchomienia, zakończenia, restarty. Platforma przechowuje tylko ostatnie pięć zdarzeń na maszynę.
Wyobraź sobie aplikację, która pada 2,5 sekundy po każdym starcie, tak jak jedna z tych. Każdy cykl dodaje awarię i start. Po kilku cyklach lista jest pełna. Od tego momentu każde nowe zdarzenie wypycha jedno stare. Lista przesuwa się, ale zawsze zawiera mniej więcej tę samą mieszankę: kilka awarii i kilka startów.
Więc „ile awarii od początku publikacji” zwracało za każdym razem tę samą liczbę. Drugie spojrzenie widziało, powiedzmy, dwie awarie. Trzecie też widziało dwie, choć inne. Kontrola uznała, że awarie ustały, i przepuściła publikację.
Stało się tak trzy razy 25 września, w dwóch aplikacjach. Za każdym razem:
- publikacja była oznaczana jako aktywna,
- wycofanie się nie uruchomiło, bo nic nie zawiodło,
- nasz reconciler, zadanie w tle sprawdzające wdrożenia po fakcie, oznaczył wdrożenie jako błędne kilka minut później,
- a cała strona zwracała 404.
Publikacja, która zawiedzie na czas, da się odzyskać: wycofanie przywraca poprzednią wersję. Publikacja, która zawiedzie kilka minut za późno, po tym jak została uznana za sukces, już pominęła swoje wycofanie.
Jak to znaleźliśmy
Odtworzyliśmy problem lokalnie: wzięliśmy działające API, pozwoliliśmy mu zasnąć, a potem opublikowaliśmy je ponownie ze zmianą, która padała przy starcie. Kontrola stanu oznaczyła je jako aktywne.
To pasowało do produkcji: w każdej z trzech publikacji aplikacja padała sekundy po każdym starcie, a liczba awarii, którą porównywała kontrola, nigdy nie rosła między spojrzeniami.
Poprawka: porównaj najnowszą awarię, a nie liczbę
Zamiast liczyć awarie, kontrola patrzy teraz na czas najnowszej awarii od początku publikacji.
Jeśli drugie spojrzenie pokazuje jakąkolwiek awarię od początku publikacji, kontrola czeka i patrzy po raz trzeci. Jeśli najnowsza awaria przy trzecim spojrzeniu jest późniejsza niż najnowsza przy drugim, maszyna padła ponownie w międzyczasie. Nie utrzymuje się w działaniu, a publikacja kończy się błędem z komunikatem, że maszyna wielokrotnie padała od publikacji i wciąż się restartuje.
To działa niezależnie od tego, jak krótka jest lista zdarzeń. Przesuwane okno pięciu zdarzeń może ukryć, ile było awarii, ale nie może ukryć, że właśnie zdarzyła się nowa. Najnowsze zdarzenie zawsze zostaje na liście.
Z tą zmianą lokalne odtworzenie zachowuje się poprawnie: publikacja się nie udaje i zostaje przywrócony poprzedni obraz. Jest też test, który symuluje zachowanie platformy, czyli każde spojrzenie dodaje awarię i start i przycina listę do pięciu, i sprawdza, że werdykt to porażka, a nie sukces.
Co z tego wynieśliśmy
- Poznaj kształt danych, które liczysz. Liczenie na ograniczonej liście przestaje cokolwiek znaczyć, gdy lista jest pełna. Ograniczenie nie było ukryte; po prostu nie zaprojektowaliśmy kontroli wokół niego.
- Wolę pytanie „czy zdarzyło się coś nowego?” od pytania „ile się zdarzyło?”. Najnowszy znacznik czasu przetrwa obcięcie, suma nie.
- Późna porażka jest gorsza niż wczesna. Ten sam zepsuty build jest nieszkodliwy, jeśli publikacja się nie powiedzie i wycofa, a kładzie stronę, jeśli najpierw zostanie uznany za sukces.
- Odtwarzaj w prawdziwych warunkach. Błąd wymagał maszyny, która już padła wystarczająco wiele razy, by zapełnić listę zdarzeń. Pojedyncza szybka awaria w teście by go nie ujawniła.
Ta poprawka łączy się z inną z tego samego dnia, która zadbała o to, by wycofanie przywracało starą wersję zamiast ją usuwać: nieudana ponowna publikacja nigdy nie usuwa działającego backendu. Jeśli Twoja aplikacja nie publikuje się, bo pada przy starcie, najlepszym miejscem na początek są rozwiązywanie problemów z publikacją w dokumentacji i nasz poradnik o debugowaniu aplikacji zbudowanej przez AI.