Cron to jedyny element sklepu, którego awarii nikt nie zauważa od razu. Strona się otwiera, koszyk działa, zamówienia wpadają do panelu — a mimo to klienci nie dostają potwierdzeń, promocja ustawiona na poniedziałek nie startuje, a ceny w panelu i na sklepie się rozjeżdżają. Sklep nie jest zepsuty. Po prostu nikt nie wykonuje pracy, którą zaplanował.
Co właściwie robi cron
Magento odkłada na później wszystko, co nie musi wydarzyć się w trakcie kliknięcia klienta. Dzięki temu strona odpowiada szybko — ale też dzięki temu lista rzeczy zależnych od cronu jest długa:
- Maile transakcyjne — potwierdzenia zamówień, faktury, powiadomienia o wysyłce
- Reguły cenowe i promocje — także ich automatyczne włączanie i wyłączanie w zaplanowanych terminach
- Indeksy — jeśli indeksator działa w trybie „Update by Schedule”
- Mapa witryny — generowanie pliku sitemap.xml
- Porządki — czyszczenie starych logów, sesji, koszyków i wpisów samego harmonogramu
- Kolejki wiadomości — zadania przetwarzane asynchronicznie
Warto zwrócić uwagę na jedną rzecz z tej listy: indeksy. Jeżeli indeksator jest ustawiony na „Update by Schedule” — a tak konfiguruje się sklepy, w których zależy nam na wydajności zapisu — to bez cronu zmiana wprowadzona w panelu nigdy nie dotrze na sklep. Dotyczy to również stanów magazynowych i ilości dostępnej do sprzedaży, gdzie skutki bywają najbardziej kosztowne.
Konfiguracja: jedno wejście w crontabie
Cron Magento nie jest osobnym demonem. To zwykłe zadanie systemowego crona, które co minutę wywołuje polecenie Magento:
* * * * * /usr/bin/php /sciezka/do/sklepu/bin/magento cron:run
Magento potrafi założyć ten wpis samodzielnie — służy do tego polecenie bin/magento cron:install. Dodaje ono blok oznaczony komentarzami #~ MAGENTO START i #~ MAGENTO END, dzięki czemu nie nadpisuje pozostałych zadań w crontabie. Jeśli blok już istnieje, polecenie go nie ruszy; wymuszenie nadpisania wymaga flagi --force, która i tak nie dotyka niczego poza tymi znacznikami.
Częsta obawa: „co minutę to chyba za często?”. Nie — cron:run nie wykonuje wszystkich zadań przy każdym wywołaniu. Zagląda do harmonogramu i uruchamia tylko to, czego czas właśnie nadszedł. Rzadsze wywoływanie nie odciąża serwera, tylko powoduje, że zadania zaplanowane pomiędzy uruchomieniami przeterminowują się.
Trzy grupy zadań
Zadania są podzielone na grupy, które można uruchamiać i konfigurować osobno:
default— maile, reguły cenowe, mapa witryny, porządkiindex— przebudowa indeksówconsumers— obsługa kolejek wiadomości
Pojedynczą grupę uruchamia się poleceniem bin/magento cron:run --group="index". Bywa to przydatne przy diagnozowaniu, ale w normalnej pracy nie trzeba dodawać osobnych wpisów w crontabie dla każdej grupy — jedno wywołanie cron:run obsługuje je wszystkie.
Grupa consumers ma dodatkową warstwę konfiguracji, tym razem w pliku app/etc/env.php:
'cron_consumers_runner' => [
'cron_run' => true,
'max_messages' => 10000,
'consumers' => []
]
Ustawienie cron_run na false całkowicie wyłącza uruchamianie kolejek przez cron — robi się tak wtedy, gdy konsumenci są uruchamiani w inny sposób, na przykład jako usługi nadzorowane przez supervisora. Pusta tablica consumers oznacza „wszyscy”. Listę dostępnych konsumentów pokazuje bin/magento queue:consumers:list.
Jak sprawdzić, czy to w ogóle działa
Całe życie cronu widać w jednej tabeli bazy danych: cron_schedule. Każdy wiersz to jedno zaplanowane zadanie, a kolumna status mówi, co się z nim stało:
pending— zaplanowane, czeka na swoją kolejrunning— wykonuje się właśnie terazsuccess— zakończone poprawnieerror— zakończone błędemmissed— nie doczekało się uruchomienia w wyznaczonym oknie
Pierwszy test jest banalnie prosty: czy przybywają wiersze ze statusem success i świeżą datą. Jeśli tak — cron pracuje. Jeśli w tabeli są wyłącznie wpisy pending ze starymi datami, to znaczy, że Magento planuje zadania, ale nikt ich nie uruchamia. Prawie zawsze chodzi wtedy o brakujący wpis w crontabie systemowym — typowo po migracji na nowy serwer albo po odtworzeniu środowiska z kopii.
Status „missed” i skąd się bierze
„Missed” znaczy: zadanie miało się wykonać, ale zanim do niego dotarliśmy, jego czas minął. Granicę wyznacza ustawienie Schedule Lifetime w Stores → Configuration → Advanced → System → Cron, domyślnie 15 minut.
Pojedyncze wpisy missed zdarzają się przy chwilowym obciążeniu i nie są powodem do niepokoju. Seria takich wpisów to już sygnał — i zwykle ma jedną z dwóch przyczyn. Albo cron nie uruchamia się wystarczająco często (ktoś ustawił go co 15 minut „żeby nie obciążać”), albo jedno długie zadanie blokuje kolejkę i reszta czeka, aż się przeterminuje.
Osobny przypadek to wiersz, który tkwi w stanie running od godzin. Proces, który go obsługiwał, najprawdopodobniej został ubity — na przykład przez limit pamięci albo restart serwera — i nikt nie zdążył zapisać końcowego statusu. Takie wiersze potrafią zablokować ponowne uruchomienie tego samego zadania.
Co zmieniło się w 2.4.8
Tabela cron_schedule ma skłonność do puchnięcia, a jednym ze źródeł były wpisy zadań pochodzących z modułów, których już w systemie nie ma — wyłączonych albo usuniętych. Takie sieroty nie były sprzątane i zostawały w tabeli na zawsze. Magento 2.4.8 dokłada automatyczne czyszczenie wpisów dla zadań, które przestały istnieć (zmiana oznaczona w informacjach o wydaniu numerem AC-12119). To jeden z tych drobiazgów, których nikt nie zauważa na co dzień, a które oszczędzają godzinę diagnostyki po roku pracy sklepu.
Lista kontrolna, gdy coś nie działa
Kolejność ma znaczenie — od rzeczy najczęstszych do najrzadszych:
- Czy wpis w crontabie istnieje i wskazuje właściwą ścieżkę do
bin/magento? - Czy działa jako właściwy użytkownik? Cron uruchomiony jako
rootpotrafi utworzyć pliki wvar/igenerated/, do których serwer WWW nie ma potem dostępu. To klasyk, który objawia się błędami dopiero po jakimś czasie. - Czy w
cron_scheduleprzybywają wpisysuccess? - Czy nie ma serii
missed— a jeśli jest, czy nie stoi za nią jedno długie zadanie? - Czy nie ma wiersza zablokowanego w
runningod wielu godzin? - Czy tryb indeksatorów zgadza się z oczekiwaniami —
bin/magento indexer:show-mode? - Czy kolejki są obsługiwane — ustawienie
cron_runwenv.phpnie zostało przypadkiem wyłączone?
Rzecz, o której warto pomyśleć wcześniej
Awaria cronu jest cicha i właśnie to czyni ją kosztowną. Nie ma komunikatu błędu, nie ma strony 500 — jest tylko rosnąca liczba klientów, którzy nie dostali potwierdzenia zamówienia. Bywa, że wychodzi to na jaw po kilku dniach, przy okazji zupełnie innej rozmowy.
Dlatego cron należy do rzeczy, które warto monitorować aktywnie, a nie sprawdzać przy okazji. Najprostszy wariant to alert, gdy w cron_schedule przez określony czas nie pojawi się żaden nowy wpis ze statusem success. To jeden z elementów, które w praktyce składają się na sensowne utrzymanie sklepu — obok aktualizacji, kopii zapasowych i przeglądu logów.