cron
planlæggeren i Unix, der kører kommandoer til faste tider

Foto: GiadaGiagi / Pixabay 
Foto: wal_172619 / Pixabay
Brug begrebet i en beslutning
Brug »Hvad er cron?« i en konkret beslutning. Vi kan knytte begrebet til det system, du bygger eller køber. Daglig drift af servere, mail, konti og opdateringer, så det, alle er afhængige af, forbliver kedeligt.
Undersøg antagelserne bag ordet
Brug forklaringen og det tilknyttede arbejde til at formulere spørgsmål til dit projekt. Vi kan undersøge antagelserne sammen, før et værktøj vælges. Har drevet 10 PostgreSQL- og MS SQL‑servere — 10 databaseservere udrullet og holdt i god drift
Hvad det er
cron er den tjeneste i Unix, der starter kommandoer på faste tidspunkter, uden
at nogen er logget ind for at starte dem. Hver brugers tidsplan ligger i en
crontab: en tabel i ren tekst med ét job pr. linje. Samme ord bruges om
kommandoen crontab, der installerer, viser og sletter tabellen.
POSIX standardiserer kommandoen og tabellens format, men ikke det program, der læser tabellerne. Standardens begrundelse siger ligeud, at alle henvisninger til en cron-dæmon og til cron-filer er taget ud. Hvilken dæmon der kører jobbene, er op til det enkelte system. De manualsider om cron, som siden bygger på, kommer fra cronie, hvis crontab(5) nævner Paul Vixie som forfatter og beskriver formatet som V7-standarden med en række udvidelser, der bevarer kompatibiliteten.
En linje har seks felter adskilt af mellemrum eller tabulatortegn. De fem første
siger hvornår: minut (0 til 59), time (0 til 23), dag i måneden (1 til 31),
måned (1 til 12) og ugedag (0 til 6, hvor 0 er søndag). Hvert felt er en stjerne
for alle værdier, et tal, et interval med bindestreg som 1-5 eller en
kommasepareret liste af den slags. Det sjette felt er kommandoen, som sh
udfører. Dér slutter standarden. Trin som */15, navne på tre bogstaver som
mon, 7 for søndag, en kolonne med brugernavn i systemtabeller og
forkortelser som @daily er udvidelser i cronie; en tabel, der bruger dem, er
ikke længere portabel.
crontab -e åbner din tabel i en editor, crontab -l viser den, og
crontab -r fjerner den, mens crontab fil erstatter den med indholdet af en
fil. cronie har desuden systemtabeller i /etc/crontab og /etc/cron.d/, hvor
et ekstra felt mellem tidspunkterne og kommandoen angiver, hvilken bruger jobbet
kører som. Det havde POSIX forudset: begrundelsen bemærker, at systemer afledt
af BSD sandsynligvis vil tilføje et brugerfelt.
Hvorfor det betyder noget
Meget af vedligeholdelsen af en server foregår, mens ingen kigger: gamle filer ryddes op, rapporter sendes med mail, databaser dumpes, og der tages backup. cron er standardmåden at sige »kør det her klokken tre om natten«, og værktøjet har været med i standarden siden Issue 2, som ændringshistorikken på dens POSIX-side viser. En tabel, der holder sig til POSIX-felterne, læses ens på alle systemer, der overholder standarden.
Svagheden er indbygget. Et planlagt job har intet publikum, så når det går i stykker, bliver ingen skærm rød. POSIX siger, at output og fejl, som en kommando ikke selv omdirigerer, sendes til brugeren med mail på en måde, som hver implementering selv vælger. På en vært, hvor lokal mail ikke ender nogen steder, ender fejlen heller ikke nogen steder. Det meste af besværet med cron kan føres tilbage til den tavshed.
To naboer deler nu arbejdet. På Linux-systemer, der styres af systemd, kan en
timer-unit starte det samme job og tilføjer det, cron mangler: den kan indhente
en kørsel, der blev sprunget over, mens maskinen var slukket, den kan sprede
starttidspunkter tilfældigt, og den starter aldrig en ekstra kopi af en
tjeneste, der stadig kører. Inde i PostgreSQL læser udvidelsen pg_cron de
samme tidsplaner med fem felter, og en baggrundsproces i databasen holder styr
på jobbene. Vores
projekt med en River-jobkø
er et eksempel: i oktober 2026 tæller siden 20 pg_cron-jobs under køen, som
rydder partitioner op, roterer salts og opdaterer aggregater, altså
vedligeholdelse, som siden siger hører hjemme i databasen.
Sådan ser det ud i praksis
Tag to jobs: en oprydning på hverdage og et natligt dump af en database.
Tabellen sætter først sit eget miljø, fordi et job ikke arver indstillingerne
fra din login-skal. Linjerne med NAVN=værdi og variablen MAILTO er
funktioner i cronie, ikke i POSIX.
SHELL=/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=ops@example.com
# minut time dag måned ugedag kommando
15 3 * * 1-5 find "$HOME" -name core -exec rm -f {} +
30 2 * * * flock -n /var/lock/dump-db dump-db >> "$HOME/dump.log" 2>&1
0 * * * * date +\%s >> "$HOME/hourly.log"Det første job læses som »klokken 03.15, mandag til fredag«. Det andet kører
hver nat klokken 02.30, skriver sit output og sine fejl til en log og er pakket
ind i flock -n, der giver op med det samme i stedet for at vente, når låsen
allerede er taget, så et dump, der trækker ud, aldrig får en tvilling. Det
tredje viser det escapede procenttegn: uden backslash ville cron skære
kommandoen over ved %.
Hold tabellen i en fil under versionsstyring, og installer den samlet i stedet for at rette i den direkte:
crontab jobs.cron
crontab -lDen anden kommando viser det, cron faktisk kommer til at læse. Med cronies
tilvalg -T kan du tjekke en fils syntaks, før du installerer den, og filen
skal slutte med et linjeskift.
Det samme natlige dump som systemd-timer kræver to units. Servicen siger, hvad der skal køres, og timeren siger hvornår:
# /etc/systemd/system/dump-db.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/dump-db
# /etc/systemd/system/dump-db.timer
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=10min
[Install]
WantedBy=timers.targetPersistent=true gemmer tidspunktet for den seneste kørsel på disken og starter
en kørsel, der blev sprunget over, så snart timeren er aktiv igen.
RandomizedDelaySec= lægger en tilfældig forsinkelse på op til ti minutter
oveni, så en flåde af maskiner med den samme fil ikke rammer databaseserveren i
samme sekund. systemd-analyze calendar '*-*-* 02:30:00' viser udtrykket i
normaliseret form og tidspunktet for næste udløsning, og det er den hurtigste
måde at afprøve en tidsplan på, før man stoler på den.
En tidsplan siger, hvornår et job starter, ikke om det gjorde sit arbejde. På en af vores værter med 464 MB vender vores dead man’s switch det om: en timer starter et script fire gange i timen med en tilfældig forskydning, og scriptet pinger kun en tjeneste udenfor, når hverken hukommelse eller disk er faldet under sin grænse. Når pingene udebliver, går alarmen.
Hvor det går galt
Kommandoen virker i din skal, men ikke i cron. POSIX lover kun et job
HOME, LOGNAME, PATH og SHELL, og PATH behøver kun at finde
standardværktøjerne. Intet fra din profil bliver indlæst. Løsningen er at bruge
absolutte stier eller sætte PATH øverst i tabellen og at teste jobbet i det
samme sparsomme miljø.
Fejl forsvinder. Output, der ikke omdirigeres, sendes med mail. cronie
sender det til tabellens ejer, til adressen i MAILTO eller slet ingen steder,
når MAILTO="". Løsningen er at omdirigere output til en log, som nogen læser,
og for de jobs, der betyder noget, at lade jobbet melde succes til noget, der
klager, når meldingerne udebliver, sådan som vores dead man’s switch ovenfor
gør.
Et procenttegn deler kommandoen. I kommandofeltet bliver % til et
linjeskift; kun den første linje køres, og resten sendes til den som
standardinput, så date +%s går i stykker. Løsningen er at escape tegnet som
\% eller at flytte kommandoen ind i et script og kalde det.
To dagfelter betyder enten-eller, ikke begge. Når både dag i måneden og
ugedag er begrænset, kører jobbet på enhver dag, der passer med et af dem.
POSIX’ eget eksempel, 0 0 1,15 * 1, kører på månedens første og femtende dag
og desuden hver mandag. Løsningen er kun at begrænse det ene af de to felter
eller at bruge en kalender i systemd, hvor Mon *-*-01..07 09:00 kun passer,
når både ugedagen og datoen stemmer: den første mandag i måneden.
Trin starter forfra hver time. cronie evaluerer kun et trin inden for sit
eget felt, så */35 i minutfeltet kører hver time på minut 0 og minut 35, ikke
med 35 minutters mellemrum, og */23 i timefeltet kører klokken 23 og ved
midnat. Løsningen er et trin, der går lige op i intervallet, eller en
systemd-timer med OnUnitActiveSec=, som tæller fra seneste gang, tjenesten
blev startet.
Uret skifter. cronie dokumenterer, at tidspunkter, der forsvinder, når uret
stilles om til sommertid, aldrig passer, så de jobs kører ikke, og at
tidspunkter, der kommer to gange, når uret stilles tilbage, får jobs til at køre
to gange. Løsningen er at lægge jobs uden for de timer, hvor din tidszone
skifter, eller at sætte CRON_TZ til en zone uden sommertid.
Den sidste linje mangler linjeskift. cronie forventer, at hver post slutter med et linjeskift; gør den sidste ikke det, betragter cronie tabellen som i det mindste delvis ødelagt og skriver en advarsel til syslog. Løsningen er et afsluttende linjeskift, som en indstilling i editoren eller et tjek under review kan sikre.
Kørsler overlapper. crontab-formatet har intet felt for, hvad der skal ske,
når den forrige kørsel stadig er i gang. En systemd-timer lader en tjeneste, der
stadig kører, være i fred. Er timerens næste tidspunkt passeret, mens
tjenesten kørte, starter timeren tjenesten igen, så snart den er færdig,
medmindre DeferReactivation= er sat; pg_cron lader en ny kørsel af samme job
vente, til den første er afsluttet. Løsningen for almindelig cron er en lås, som
flock -n i eksemplet ovenfor.
Maskinen var slukket. En crontab-linje angiver et øjeblik, og formatet kan
ikke udtrykke »kør det senere, hvis øjeblikket er gået«. Løsningen er, hvor
systemd styrer maskinen, Persistent=true på en timer med OnCalendar=.
Alle maskiner på én gang. En tabel, der kopieres til hundrede værter,
starter hundrede jobs i samme minut. Løsningen er RandomizedDelaySec= på en
systemd-timer eller i cronie variablen RANDOM_DELAY eller et interval med
tilde som 6~15, der vælger ét tilfældigt minut, når tabellen læses.
En crontab uden argument tømmer tabellen. Skrevet alene venter kommandoen
på en ny tabel på standardinput, og et filslut (som regel Ctrl-D) erstatter den
nuværende med ingenting. Løsningen er at trykke på afbrydelsestasten i stedet og
at holde tabellen i en fil, som du installerer med crontab fil.
Læs mere
- crontab, POSIX.1-2024 — standardens seks felter, standardmiljøet, reglen for mail og begrundelsen.
- crontab(5), cronie
— trin,
MAILTO,CRON_TZ,RANDOM_DELAY, sommertid og forbehold. - systemd.timer(5)
—
OnCalendar=,Persistent=,RandomizedDelaySec=og tjenester, der kører. - systemd.time(7) — syntaksen for kalenderhændelser, forkortelserne, og hvordan de valideres.
- flock(1)
— en lås om en kommando, med
-nfor at give op, når låsen er taget. - pg_cron — cron-tidsplaner for SQL-jobs, holdt inde i PostgreSQL som en udvidelse.

