Zielony status agenta, który nie uruchomił się ani razu
Ciao! 🇵🇱🇮🇹
W weekend chciałem wyłączyć autostart jednej aplikacji, a skończyłem przeglądem wszystkiego, co uruchamia się na moim Macu bez pytania. Znalazłem trzy zepsute rzeczy, z czego najciekawsza raportowała, że wszystko gra.
Lecimy z tematem 🚀
Status zero, czyli sukces, którego nie było
Mam na Macu ponad trzydzieści agentów launchd. To ciche zlecenia stojące w tle: sprawdź coś o tej godzinie, zsynchronizuj tamto w poniedziałek, wyślij powiadomienie, gdy coś się zmieni. Pisałem je przez ostatni rok i przestałem o nich myśleć, bo dokładnie od tego są.
Kliknąłem w listę tylko dlatego, że chciałem uciszyć jedną aplikację muzyczną. Poszło szybciej, niż zakładałem, więc zajrzałem dalej.
launchctl list ma kolumnę ze statusem ostatniego uruchomienia. Przy moich agentach było tam wszędzie zero. Zero to sukces. Wyglądało dobrze przez jakieś dwie minuty.
Bo jeden z nich, ten wrzucający statystyki postów LinkedIn do Notion, miał zero i nie uruchomił się ani razu od dnia, w którym przeniosłem projekt do innego katalogu. Nie raz na jakiś czas. Ani razu.
Mechanizm jest głupszy, niż się wydaje. Kolumna pokazuje kod wyjścia OSTATNIEGO uruchomienia, a agent, który w tej sesji systemu jeszcze się nie odpalił, ma tam zero z rozpędu. Nie dlatego, że mu się udało. Dlatego, że nie ma czego raportować, a zero jest wartością domyślną.
Pod spodem czekały cztery niezależne usterki ułożone jedna na drugiej. Ścieżka do skryptu prowadziła w katalog, którego już nie ma. Ścieżki logów prowadziły w to samo miejsce, więc błąd zapisywał się w nicość. Interpreter wskazany w konfiguracji to systemowy /usr/bin/python3, który nie ma biblioteki requests, więc skrypt i tak wywaliłby się w trzeciej linijce. A na jego końcu siedziało input() czekające na potwierdzenie z klawiatury, której launchd nigdy nie ma.
Cztery powody, żeby nie zadziałać. Zero jako status.
Dwa pozostałe znaleziska były bardziej hałaśliwe i równie niewidoczne. Agent po dawno usuniętej aplikacji do synchronizacji budził się co godzinę od listopada zeszłego roku, zwracał kod 127 i przez ten czas napisał ćwierć megabajta błędów do pliku w moim katalogu domowym. Nigdy go nie otworzyłem. Drugi to updater przeglądarki, której już nie mam, wołający co godzinę binarkę, której nie ma.
Jeśli chcesz sprawdzić to u siebie, nie patrz na statusy. Sprawdź, czy pliki wskazane w konfiguracji w ogóle istnieją:
for p in ~/Library/LaunchAgents/*.plist; do
bin=$(/usr/libexec/PlistBuddy -c "Print :ProgramArguments:0" "$p" 2>/dev/null)
[ -n "$bin" ] && [ ! -e "$bin" ] && echo "MARTWY: $p -> $bin"
done
Sama naprawa była nudna: nowe ścieżki, interpreter z Frameworków zamiast systemowego, input() owinięte w try/except EOFError. Dwa martwe agenty poszły do kosza. Do rutyny po każdej przeprowadzce katalogu dopisałem sobie jedną linijkę: grep -rl "stara-nazwa" ~/Library/LaunchAgents/.
Została mi z tego zasada szersza niż launchd. Kod wyjścia opisuje proces, a mnie interesuje robota, którą ten proces miał wykonać. Więc jeśli automat ma coś wyprodukować, pytam teraz o produkt: świeży wpis w bazie, plik z dzisiejszą datą, wysłany mail. Agenta od LinkedIna sprawdzam po dacie ostatniego rekordu w Notion, a w statusy nie zaglądam wcale.
🛠️ Narzędzie
PlistBuddy
Wbudowany w macOS edytor plików .plist, siedzący w /usr/libexec/PlistBuddy, o którym mało kto wie, bo nie ma go w PATH. Wyciąga dowolne pole z konfiguracji jedną komendą, więc nadaje się do pętli po wszystkich agentach naraz, zamiast otwierania trzydziestu plików po kolei. Użyłem go do wypisania interpretera i ścieżki skryptu z każdego pliku, żeby sprawdzić, które z nich celują w pustkę. Działa też na Info.plist aplikacji, gdy chcesz szybko sprawdzić wersję albo identyfikator paczki.
/usr/libexec/PlistBuddy -c "Print" plik.plist
🌍 Ze świata
- Exit code 0 is a lie: 7 ways my unattended automation silently did nothing. Youfu Hsu opisuje trzydzieści zaplanowanych zadań, które tygodniami kończyły się sukcesem i nie wyprodukowały ani jednego pliku. Rada z tekstu jest ta sama, do której doszedłem po swojemu: sprawdzaj artefakt, nie status.
- Why Cron Jobs Fail Silently. Odwrócenie zależności, o którym tu mowa, jest sprytne. Zadanie samo melduje, że żyje, a alarmem staje się cisza.
- Manage login items and background tasks on Mac. Dokumentacja Apple, nudna jak każda dokumentacja. Za to jedyne miejsce, gdzie znalazłem czarno na białym, co pokazuje
sfltool dumpbtm, czyli komenda wypisująca wszystko, co startuje przy logowaniu.
😄 Na koniec

Mój agent od LinkedIna stemplował sobie zaliczone co tydzień, a skryptu, który miał uruchomić, nie było pod tym adresem od miesięcy.
Zielony status to opinia programu o samym sobie.
Jeśli ktoś w Twoim otoczeniu powinien to przeczytać, prześlij mu ten numer. To najlepsza forma wsparcia.
A jeśli wolisz wesprzeć bezpośrednio: postaw mi kawę.
Cieszę się, że tu jesteś! Aby nie przegapić kolejnych wpisów i pomóc mi tworzyć więcej takich treści, dołącz do grona subskrybentów. To nic nie kosztuje.
Dołącz do Marini Brief →