Jak czytać wyrażenie cron

Objaśnienie pięciu pól cron wraz z zakresami, krokami, listami, nazwami i skrótami, a do tego reguła dnia miesiąca i dnia tygodnia, która zaskakuje wszystkich.

Wyrażenie cron to pięć wartości rozdzielonych spacjami, czytanych od lewej do prawej jako minuta, godzina, dzień miesiąca, miesiąc, dzień tygodnia. Zadanie uruchamia się wtedy, gdy bieżący czas pasuje do każdego pola.

30 4 * * 1
│  │ │ │ │
│  │ │ │ └── day of week (1 = Monday)
│  │ │ └──── month (any)
│  │ └────── day of month (any)
│  └──────── hour (4am)
└─────────── minute (30)

To wyrażenie czyta się jako "o 04:30 w każdy poniedziałek".

Pięć pól

#PoleDozwolone wartościUwagi
1Minuta0 do 59
2Godzina0 do 23Zegar 24 godzinny, 0 to północ
3Dzień miesiąca1 do 31
4Miesiąc1 do 12 albo JAN do DEC
5Dzień tygodnia0 do 6 albo SUN do SAT0 to niedziela, a większość implementacji cron przyjmuje również 7

Część harmonogramów używa innego kształtu. Quartz, wykorzystywany przez wiele oprogramowania javowego, stawia sekundy na początku i dokłada opcjonalny rok, a dni tygodnia numeruje od 1 do 7, zaczynając od niedzieli. Jeśli wyrażenie ma sześć albo siedem pól, sprawdź, dla którego systemu zostało napisane, zanim zaufasz swojemu odczytowi.

Operatory

Są cztery i łączą się ze sobą wewnątrz pojedynczego pola.

SymbolNazwaPrzykładZnaczenie
*Dowolna wartość* * * * *Co minutę każdego dnia
,Lista0 9,13,17 * * *O 09:00, 13:00 i 17:00
-Zakres0 9-17 * * *Co godzinę od 09:00 do 17:00 włącznie
/Krok*/15 * * * *O :00, :15, :30 i :45

Krok zawsze stosuje się do zakresu. */15 w polu minuty oznacza "zaczynając od 0, bierz co piętnastą wartość aż do 59". Krok można nałożyć również na jawny zakres: 5-30/10 daje 5, 15 i 25, a potem się kończy, ponieważ 35 wykracza poza koniec.

Kroki nie oznaczają "co 15 minut od teraz"; wybierają stałe wartości z tarczy zegara. */40 odpala o :00 i :40, a potem czeka tylko 20 minut na :00 kolejnej godziny, ponieważ zliczanie zaczyna się od nowa w każdej godzinie. Listy mogą zawierać zakresy i kroki, więc 0 0-6/2,12,18-23 * * * jest poprawnym polem godziny.

Nazwy i skróty

Pola miesiąca i dnia tygodnia przyjmują trzyliterowe nazwy, a wielkość liter nie ma znaczenia, więc JAN, jan i Jan to to samo. Klasyczna dokumentacja crontab mówi, że zakresy i listy nazw nie są dozwolone, choć wiele nowoczesnych implementacji przyjmuje MON-FRI. Jeśli nie masz pewności, co uruchamia twoje zadanie, używaj liczb: 1-5 jest jednoznaczne wszędzie.

Kilka skrótów zastępuje całe pięciopolowe wyrażenie:

SkrótOdpowiednikUruchamia się
@yearly albo @annually0 0 1 1 *O północy 1 stycznia
@monthly0 0 1 * *O północy pierwszego dnia miesiąca
@weekly0 0 * * 0O północy w niedzielę
@daily albo @midnight0 0 * * *O północy codziennie
@hourly0 * * * *O pełnej godzinie

Istnieje również @reboot, ale nie jest to harmonogram: uruchamia zadanie raz, w chwili startu samego crona.

Pułapka dnia miesiąca i dnia tygodnia

To ta, która gryzie. Kiedy zarówno pole dnia miesiąca, jak i pole dnia tygodnia są ograniczone, czyli żadne z nich nie jest *, cron uruchamia zadanie wtedy, gdy pasuje którekolwiek z nich, a nie wtedy, gdy pasują oba.

0 0 13 * 5

Można to odczytać jako "o północy w piątek trzynastego". W rzeczywistości oznacza to "o północy trzynastego dnia każdego miesiąca, a także o północy w każdy piątek": ponad sześćdziesiąt uruchomień rocznie zamiast jednego albo dwóch.

Oczekiwane zachowanie koniunkcji obowiązuje wyłącznie wtedy, gdy jedno z tych dwóch pól jest *. Zatem 0 0 * * 5 to każdy piątek, a 0 0 13 * * to każdy trzynasty dzień miesiąca, i oba są całkowicie normalne. To ograniczenie obu pól naraz włącza alternatywę.

Nie ma standardowego sposobu na wyrażenie "piątku trzynastego" w pięciu polach. Zwykłym obejściem jest zaplanowanie zadania na każdego trzynastego i sprawdzanie w samym zadaniu dnia tygodnia przed wykonaniem jakiejkolwiek pracy.

Pokrewna subtelność: część implementacji rozstrzyga, czy pole jest ograniczone, sprawdzając, czy dosłownie zaczyna się od *. Przy takich implementacjach 0-6 w polu dnia tygodnia liczy się jako ograniczenie, choć obejmuje każdy dzień, i po cichu włącza zachowanie alternatywy. Gdy masz na myśli "dowolny", używaj *.

Błędy, których warto szukać

  • * */2 * * * uruchamia zadanie co minutę w co drugiej godzinie: 720 uruchomień dziennie. Chodziło ci o 0 */2 * * *, czyli o 12.
  • Brakujące pole minuty przesuwa wszystko o jedno w lewo i zwykle nadal się parsuje, dając poprawny harmonogram o zupełnie błędnej porze.
  • 0 0 31 * * po cichu pomija miesiące, które nie mają trzydziestego pierwszego dnia.
  • Cron używa strefy czasowej systemu albo użytkownika, chyba że harmonogram pozwala ją ustawić. Kiedy zegary przesuwają się z powodu czasu letniego, zadanie z pominiętej godziny może w ogóle się nie uruchomić, a zadanie z godziny powtórzonej może uruchomić się dwa razy, zależnie od implementacji. Zadania, które muszą wykonać się raz dziennie, najbezpieczniej planować z dala od nocnych godzin, na które przypada przesunięcie.

W razie wątpliwości odczytaj wyrażenie z powrotem jako zdanie, a potem sprawdź kilka najbliższych terminów, w których naprawdę by odpaliło. Jeśli te daty nie są tym, co opisałeś, błędne jest wyrażenie, a nie twój odczyt.