Wyrażenia cron: pięć pól, z przykładami
Wyrażenie cron to pięć oddzielonych spacjami pól, które mówią, kiedy zadanie ma się uruchomić: minuta, godzina, dzień miesiąca, miesiąc, dzień tygodnia. Czytane od lewej do prawej, 30 2 * * 1 oznacza minutę 30 godziny 2, w dowolnym dniu dowolnego miesiąca, jeśli ten dzień jest poniedziałkiem.
Pięć pól
Każda standardowa linia cron w Uniksie zaczyna się od tych samych pięciu pól, po których następuje polecenie do uruchomienia.
* * * * * command to run
| | | | |
| | | | +-- day of week (0-7, 0 and 7 both mean Sunday, or SUN-SAT)
| | | +---- month (1-12, or JAN-DEC)
| | +------ day of month (1-31)
| +-------- hour (0-23)
+---------- minute (0-59)
Pole przyjmuje jedną z czterech postaci: gwiazdkę oznaczającą każdą wartość, pojedynczą liczbę, listę albo zakres. Godziny używają zegara 24-godzinnego, bez AM czy PM, więc 18:00 to 18. Niedziela to zarówno 0, jak i 7, bo różne systemy historycznie się co do tego nie zgadzały, a cron akceptuje obie wartości.
Niektóre schedulery dodają pola. Quartz, używany przez wiele frameworków Javy, umieszcza pole sekund na początku i dodaje opcjonalny rok na końcu, więc wyrażenie o sześciu lub siedmiu polach skopiowane z dokumentacji Quartz nie zadziała w linuksowym crontabie. Zanim skądkolwiek skopiujesz wyrażenie, sprawdź, dla jakiej odmiany crona je piszesz.
Znaki specjalne
*dopasowuje każdą wartość w polu.* * * * *uruchamia zadanie co minutę.,tworzy listę wartości.0 8,13,20 * * *uruchamia zadanie o 08:00, 13:00 i 20:00.-zadaje zakres.0 9-17 * * *uruchamia zadanie co godzinę od 09:00 do 17:00./przechodzi przez zakres z krokiem.*/15 * * * *uruchamia zadanie w minutach 0, 15, 30 i 45. Można to łączyć z zakresem:0 9-17/2 * * *uruchamia zadanie o 9, 11, 13, 15 i 17.- Nazwy.
MONdoSUNorazJANdoDECdziałają w dwóch ostatnich polach i czyta się je lepiej niż liczby. Nie można ich używać wewnątrz kroku.
Cztery kolejne znaki pojawiają się bez przerwy w tutorialach i nie istnieją w standardowym cronie. L dla ostatniego dnia, W dla najbliższego dnia roboczego, # dla n-tego dnia tygodnia w miesiącu oraz ? zamiast gwiazdki to rozszerzenia Quartz. Wyrażenie takie jak 0 0 L * * zostanie odrzucone przez linuksowy crontab. Żeby uruchomić coś w ostatnim dniu miesiąca w takim środowisku, uruchamiaj to codziennie i pozwól poleceniu podjąć decyzję:
0 0 * * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end.sh
Zwróć uwagę na ukośniki wsteczne w tej linii. Znak procenta ma w crontabie specjalne znaczenie, co jest piątym błędem opisanym poniżej.
Cron akceptuje też sześć skrótowych ciągów zamiast wszystkich pięciu pól: @yearly (zapisywane też @annually), @monthly, @weekly, @daily (też @midnight), @hourly oraz @reboot, który uruchamia się raz przy starcie crona, a nie zgodnie z zegarem. @reboot nie jest wspierany wszędzie.
Typowe harmonogramy
| Kiedy chcesz, żeby zadanie się uruchomiło | Wyrażenie |
|---|---|
| Co minutę | * * * * * |
| Co 5 minut | */5 * * * * |
| Co 30 minut | 0,30 * * * * |
| Co godzinę, o pełnej godzinie | 0 * * * * |
| Co 2 godziny | 0 */2 * * * |
| Codziennie o północy | 0 0 * * * |
| Codziennie o 02:30 | 30 2 * * * |
| Dwa razy dziennie, 08:00 i 20:00 | 0 8,20 * * * |
| W dni robocze o 09:00 | 0 9 * * MON-FRI |
| Co godzinę w godzinach pracy, w dni robocze | 0 9-17 * * MON-FRI |
| W każdy poniedziałek o 07:00 | 0 7 * * MON |
| W każdą niedzielę o 03:15 | 15 3 * * SUN |
| Pierwszego dnia miesiąca o 06:00 | 0 6 1 * * |
| Kwartalnie, pierwszego stycznia, kwietnia, lipca, października | 0 0 1 1,4,7,10 * |
Błędy, przez które zadanie uruchamia się o złej porze
- Wypełnienie obu pól dnia. To ten błąd, który łapie każdego. Gdy dzień miesiąca i dzień tygodnia mają oba ustawioną wartość inną niż gwiazdka, cron uruchamia zadanie, gdy pasuje którykolwiek z nich, a nie oba naraz.
0 0 13 * FRIuruchamia się każdego 13. i każdego piątku, nie tylko w piątek trzynastego. - Krok, który nie dzieli się równo w zakresie.
*/7 * * * *uruchamia zadanie w minutach 0, 7, 14, 21, 28, 35, 42, 49 i 56, a potem zaczyna od nowa od 0. Odstęp na granicy godziny wynosi cztery minuty, nie siedem. Ta sama pułapka dotyczy*/40w polu minut i każdego kroku, który nie jest dzielnikiem 60. - Umieszczenie kroku w złym polu.
*/2 * * * *to co dwie minuty.0 */2 * * *to co dwie godziny. Pominięcie wiodącego0zamienia zadanie godzinowe w zadanie uruchamiane 30 razy częściej. - Zakładanie środowiska. Cron daje zadaniu minimalne środowisko, zwykle niewiele więcej niż
PATH=/usr/bin:/biniSHELL=/bin/sh. Skrypt, który działa w Twoim shellu, zawodzi w cronie, bo wywołuje coś z/usr/local/bin. Używaj ścieżek bezwzględnych zarówno dla samego polecenia, jak i wewnątrz niego. - Nieopisany znak procenta. W crontabie
%jest zamieniany na znak nowej linii, a wszystko po pierwszym takim znaku trafia do polecenia jako standardowe wejście.date +%Y-%m-%dw linii crontaba trzeba zapisać jakodate +\%Y-\%m-\%d. - Ignorowanie wyjścia. Wszystko, co zadanie wypisze, jest wysyłane mailem do właściciela crontaba, a na maszynie bez skonfigurowanej poczty jest po prostu odrzucane. Wyślij to gdzieś, gdzie to przeczytasz:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 - Dopuszczenie nakładania się uruchomień. Cron startuje kolejne uruchomienie zgodnie z harmonogramem, niezależnie od tego, czy poprzednie się zakończyło. Opakuj długie zadania w blokadę:
*/5 * * * * flock -n /tmp/sync.lock /usr/local/bin/sync.sh - Zapomnienie o zmianie czasu. Cron używa lokalnego czasu maszyny. W dniach zmiany czasu godzina wokół 02:00 albo nie istnieje, albo zdarza się dwukrotnie, więc zadanie zaplanowane w tym oknie może zostać pominięte albo uruchomione dwa razy, zależnie od implementacji crona. Ustaw serwery na UTC albo planuj zadania poza tym oknem.
- Wpisanie
crontab -r. Usuwa cały crontab bez żadnego potwierdzenia, a leży jeden klawisz odcrontab -e. Trzymaj crontab w systemie kontroli wersji i instaluj go z pliku.
Sprawdź to z zewnątrz
Wyrażenie, które się parsuje, to nie to samo co zadanie, które się wykonało. Sprawdź obie rzeczy, najpierw na maszynie, a potem spoza niej.
Na maszynie potwierdź, co jest zainstalowane, co pokazuje zegar i czy cron uruchomił zadanie:
crontab -l
timedatectl
grep CRON /var/log/syslog | tail -20
journalctl -u cron -u crond --since "2 hours ago"
Linia w logu dowodzi, że cron uruchomił polecenie. Nie mówi nic o tym, czy polecenie się powiodło, dlatego przekierowanie do pliku logu z listy błędów powyżej ma znaczenie.
Następnie sprawdź wynik tak, jak zrobiłby to użytkownik, z zewnątrz serwera. Większość zaplanowanych zadań istnieje po to, żeby zmienić coś obserwowalnego: feed, który powinien nosić dzisiejszą datę, mapę strony, która powinna zostać przepisana, eksport, który powinien się pojawić. Zażądaj go i przeczytaj nagłówki:
curl -sI https://example.com/exports/daily.json
curl -s https://example.com/health/last-run
Nagłówek Last-Modified mówi, czy plik jest świeży, i robi to bez dostępu do powłoki. Uruchomienie tego samego żądania z kilku lokalizacji za pomocą kontroli HTTP odróżnia zadanie, które się nie wykonało, od strony zbuforowanej na brzegu sieci w jednym regionie i nieaktualnej tylko tam. Tego rozróżnienia nie widać z pojedynczego curl na samym serwerze.
Jak poznać, że zaplanowane zadanie przestało działać
Zadanie cron, które przestaje działać, nie zostawia niczego do zauważenia. Nie ma strony błędu ani nieudanego żądania, więc nic nie wywoła alertu, jeśli coś nie obserwuje jego nieobecności. Monitorujesz efekt zadania, a nie samo zadanie: plik stanu, który przepisuje, znacznik czasu, który publikuje, endpoint raportujący jego ostatnie udane uruchomienie. Zaplanowana kontrola tego endpointu zamienia cichą awarię w powiadomienie, a HostTracker wysyła je e-mailem, SMS-em, telefonicznie, przez Slack, Telegram i więcej, w ramach 13 typów monitorów. Mechanika konfiguracji takiej kontroli znajduje się w przewodniku po kontroli HTTP, pozostałe przewodniki rozwiązywania problemów są w klastrze napraw, a pełna lista typów kontroli jest na stronie funkcji.