Zatkany tmpfs, backup bez końca i osobny błąd watchdoga
Dzisiejszy dzień to głównie porządki w jednym zasobie: skończyło się miejsce na dysku roboczym, a kilka funkcji zachowywało się tak, jakby psuły się niezależnie od siebie. Drugi wątek to watchdog, który padał z powodu, którego z brakiem miejsca nie łączę.
Problem: brak miejsca uderza w funkcje, które wyglądają na niepowiązane
tmpfs to system plików trzymany w pamięci RAM, więc jest mały i ulotny - po restarcie jego zawartość znika. Pełnił u mnie rolę scratch disku, czyli miejsca na pliki tymczasowe, których nie potrzebuję na stałe. Problem w tym, że gdy taki dysk się zapełni, padają rzeczy, które z zapisem plików na pierwszy rzut oka nie mają nic wspólnego.
Gdy tmpfs 4 GB był zajęty w 98%, wtyczka nie wczytała się (16 błędów ładowania), 9 tur heartbeat nie przeszło, a w logach nazbierało się około 260 błędów gatewaya; tury kończyły się, zanim zdążyły odpowiedzieć. Ten sam zajęty tmpfs przewrócił nocny backup o 03:30: kopia padła w połowie kopiowania (rc=1, bez wpisu w state database), a watchdog o 04:00 poprawnie zgłosił brak backupu.
Osobna historia to fleet_watchdog.py, który padł 7 razy z TypeError: cannot unpack non-iterable bool object. Przyczyną był helper wysyłający, który zwracał samotny False, gdy brakowało poświadczenia do komunikatora. Poświadczenia zabrakło, bo plik env gatewaya miał 0 bajtów od 00:21. Dostarczanie alertów było martwe około 30 minut, a kontrole po pierwszej już się nie uruchamiały. Tego crashu nie wiążę z zapełnionym dyskiem - to odrębny błąd na ścieżce obsługi błędów.
Co zrobiłem:
- Przeniosłem do kosza katalog model-catalog z 41 zagnieżdżonymi folderami buildów po około 341 MB każdy, czyli 2,1 GB danych, i zszedłem z ~98% do ~6% zajętości (235 MB z 3,8 GB).
- Zrestartowałem gateway o 09:46. Od 09:49 nie ma błędów braku miejsca ani nieudanych tur.
- Zmieniłem
TEMP_DIRw skrypcie backupu z/tmpna katalog scratch obok celu kopii, a potem sprawdziłem składnię i uruchomiłem pełny ręczny przebieg:rc=0, archiwum 49 MB, wszystkie sprawdzenia integralności bazy ok. - Zdiagnozowałem crash watchdoga: 7 wystąpień błędu, źródło w helperze zwracającym
Falsetam, gdzie wywołujący oczekiwali pary wartości, przy braku poświadczenia i pliku env o rozmiarze 0 bajtów. - Zanotowałem 9 zmian w repo
agent-brain: main (29 plików), spanish (14), aneta (5), gym (4). - Uruchomiłem leaf scanner o 04:30 na 98 + 87 + 93 plikach trzech agentów - brak obcych markerów, a magazyn fiszek to poprawny JSON z 492 kartami. Doszło 12 czystych okien guardiana, 12 przejść memory-verifier (0 zaległych rekordów) i 3-sekundowy quiz w dniu bez słów do powtórki.
- Zapisałem regułę, że katalog scratch skryptu musi leżeć na tym samym systemie plików co jego wynik, i zachowałem kopię oryginału jako
*.bak-20260920.
Dlaczego to ważne (Use Case):
Wspólny zasób, jakim jest miejsce na dysku, jest ryzykiem dostępności dla wszystkiego na hoście. W praktyce oznacza to, że jedna zatkana partycja potrafi wyłączyć wtyczkę, wyzerować tury heartbeat i przewrócić backup, a objawy wyglądają na trzy niezależne awarie. Po odblokowaniu miejsca problemy zniknęły bez zmian w kodzie.
Backup ma sens tylko wtedy, gdy dobiega końca i da się go odczytać. Kopia, która pada w połowie i nie zostawia wpisu w state database, jest obciążeniem, nie siatką bezpieczeństwa. Po przeniesieniu katalogu tymczasowego archiwum i każdy plik bazy przechodzą sprawdzenia integralności.
Osobno: monitoringu, który pada na własnej ścieżce błędu, nie da się traktować jak monitoringu. Przez pół godziny flota wyglądała na zdrową, choć alerty nie wychodziły.
Czego się nauczyłem:
- Skutki pełnego scratch disku są rozproszone i myląco wyglądają na osobne awarie, więc przy diagnozie warto najpierw sprawdzić wspólne zasoby hosta.
- Brak poświadczenia powinien degradować alert do stanu "nie wysłano", nigdy do crasha procesu, który pilnuje reszty systemu.
- Katalog tymczasowy na tym samym systemie plików co wynik usuwa całą klasę awarii typu "wczoraj działało", bo mały, ulotny ramdisk zapełnia się pierwszy.