Zespół wdrażający 5,5 MB runtime'u Pythona w przeglądarkach odkrył, że 69% błędów zarejestrowanych podczas ostatniego sprintu figurowało pod jednym, mylącym tytułem, a 89% z nich to w rzeczywistości były przekroczenia czasu połączenia sieciowego (timeouts). Błędne raportowanie skierowało deweloperów na niewłaściwą ścieżkę debugowania i pozostawiło znaczną część użytkowników z cichymi błędami pobierania — problemem, który każda aplikacja webowa pakująca duże zasoby może wkrótce powtórzyć.

Dashboard wprowadzał w błąd

System śledzenia błędów automatycznie grupuje incydenty według lokalizacji kodu, w której pojawiają się po raz pierwszy. Powstały tytuł wyglądał jak zwykły błąd w loaderze runtime'u, więc cały sprint poświęcono na szukanie ścieżek kodu, które nigdy nie ulegały przekroczeniu czasu połączenia. Gdy zespół przeanalizował metadane, wyłonił się prawdziwy obraz: większość awarii wcale nie była błędami, lecz zawieszonymi połączeniami sieciowymi, które wywołały timeout.

Wniosek: Tytuł błędu to jedynie ułatwienie, a nie diagnoza. Okresowo zagłębiaj się w surowe dane, aby zweryfikować, co faktycznie reprezentuje nagłówek.

API połączenia przeglądarki podawało wartość zastępczą

Aby nie zmuszać użytkowników z wolnym łączem do pobierania 5,5 MB, deweloperzy skorzystali z Network Information API przeglądarki (navigator.connection). API zgłaszało stałą przepustowość 1,7 Mbps dla każdego nowego użytkownika.

Przeglądarki podają wartość domyślną, gdy nie mają danych historycznych dla nowego użytkownika. Ta wartość domyślna to jedynie wskazówka, a nie rzeczywista prędkość. Gdy ta sama wartość zastępcza pojawia się przy każdej nowej sesji, oznacza to, że API nie zostało jeszcze skalibrowane dla danej grupy odbiorców.

Wniosek: Traktuj każdy sygnał sieciowy, który nigdy się nie zmienia, jako wartość rezerwową (fallback), a nie jako definitywną metrykę.

Pojedyncze migawki są niewiarygodne

Po odrzuceniu niewiarygodnej wskazówki dotyczącej przepustowości, zespół przeszedł na inny sygnał, który wydawał się działać w ich zestawie testowym. Jedno uruchomienie testu zakończyło się sukcesem, ale powtórzenie go trzy razy za każdym razem kończyło się błędem. Prędkość sieci stale się waha. Kod wykonał pojedynczą migawkę (snapshot), podjął stałą decyzję, a następnie kontynuował działanie, nawet jeśli połączenie zmieniło się chwilę później.

Wniosek: Nie opieraj trwałej decyzji na pojedynczym odczycie zmiennej wartości. Zamiast jednorazowego odpytywania (polling), subskrybuj zdarzenia zmian.

Praktyczne poprawki wdrożone przez zespół

  • Subskrybowanie zmian połączenia. Zamiast jednorazowego odczytu navigator.connection, kod nasłuchuje teraz zdarzenia change i reaguje, jeśli przepustowość spadnie lub wzrośnie podczas pobierania.
  • Dodanie mechanizmu typu „watchdog” monitorującego brak postępu. Timer przerywa każde żądanie, które nie wykazuje postępu po krótkim interwale, pozwalając przeglądarce na ponowienie próby lub przejście do trybu awaryjnego.
  • Zaprzestanie przełączania CDN-ów w trakcie pobierania. Zmiana źródła dużego pliku przy wolnym łączu powoduje restart transferu od zera, marnując już pobrane bajty. Pobieranie trzyma się początkowo wybranego CDN przez cały czas trwania procesu.
  • Odroczenie ciężkich operacji buforowania. Zadania zapisujące duże ilości danych do pamięci podręcznej są odkładane do momentu zakończenia ładowania runtime'u, co skraca ścieżkę krytyczną.

Jeśli Twoje dashboardy malują niepokojąco uporządkowany obraz, drąż głębiej. Jeśli pomiar sieciowy nigdy się nie zmienia, traktuj go jako wartość zastępczą. A jeśli pojedyncza migawka decyduje o losie wielomegabajtowego pobierania, stawiasz wszystko na miraż. Takie zakłady objawiają się jako ciche błędy, które niszczą zaufanie użytkowników — czego nie naprawi nawet najsprytniejszy kod po fakcie.