cron
schemaläggaren i Unix som kör kommandon på bestämda tider

Foto: GiadaGiagi / Pixabay 
Foto: wal_172619 / Pixabay
Använd begreppet i ett beslut
Använd ”Vad är cron?” i ett konkret beslut. Vi kan knyta begreppet till systemet du bygger eller köper. Daglig skötsel av servrar, e-post, konton och uppdateringar, så att det som alla förlitar sig på förblir odramatiskt.
Granska antagandena bakom ordet
Använd förklaringen och det länkade arbetet för att formulera frågor till projektet. Vi kan undersöka antagandena tillsammans innan ett verktyg väljs. Drev 10 PostgreSQL- och MS SQL‑servrar på Ubuntu — 10 databasservrar som driftsattes och hölls i gott skick
Vad det är
cron är tjänsten i Unix som startar kommandon vid bestämda tider, utan att någon behöver vara
inloggad för att starta dem. Varje användares schema finns i en crontab: en tabell i ren text med
ett jobb per rad. Samma ord används om kommandot crontab, som installerar, visar och tar bort
tabellen.
POSIX standardiserar kommandot och tabellformatet, men inte programmet som läser tabellerna. Standardens motivering säger rakt ut att alla hänvisningar till en cron-demon och till cron-filer har tagits bort. Vilken demon som kör jobben är upp till varje system. Manualsidorna om cron som den här sidan bygger på kommer från cronie, vars crontab(5) anger Paul Vixie som upphovsman och beskriver formatet som V7-standarden med ett antal utökningar som behåller kompatibiliteten.
En rad har sex fält åtskilda av blanksteg eller tabbar. De fem första anger när: minut (0 till 59),
timme (0 till 23), dag i månaden (1 till 31), månad (1 till 12) och veckodag (0 till 6, där 0 är
söndag). Varje fält är en asterisk för alla värden, ett tal, ett intervall med bindestreck som 1-5
eller en kommaseparerad lista av sådana. Det sjätte fältet är kommandot, som sh kör. Där slutar
standarden. Steg som */15, namn på tre bokstäver som mon, 7 för söndag, en kolumn med
användarnamn i systemtabeller och förkortningar som @daily är utökningar i cronie; en tabell som
använder dem är inte längre portabel.
crontab -e öppnar din tabell i en editor, crontab -l skriver ut den och crontab -r tar bort
den, medan crontab fil ersätter den med innehållet i en fil. cronie har dessutom systemtabeller i
/etc/crontab och /etc/cron.d/, där ett extra fält mellan tiderna och kommandot anger vilken
användare jobbet körs som. Det hade POSIX förutsett: motiveringen noterar att system som härstammar
från BSD sannolikt kommer att lägga till ett användarfält.
Varför det spelar roll
Mycket av underhållet av en server sker medan ingen tittar: gamla filer rensas bort, rapporter skickas med e-post, databaser dumpas och säkerhetskopior tas. cron är standardsättet att säga ”kör det här klockan tre på natten”, och verktyget har funnits i standarden sedan Issue 2, vilket ändringshistoriken på dess POSIX-sida visar. En tabell som håller sig till POSIX-fälten läses likadant på alla system som följer standarden.
Svagheten är inbyggd. Ett schemalagt jobb har ingen publik, så när det går sönder blir ingen skärm röd. POSIX säger att utdata och fel som ett kommando inte själv omdirigerar skickas till användaren med e-post, på ett sätt som varje implementation väljer själv. På en värd där lokal e-post inte når någonstans hamnar felet inte heller någonstans. Det mesta besväret med cron kan härledas till den tystnaden.
Två grannar delar nu på arbetet. På Linux-system som styrs av systemd kan en timerenhet starta samma
jobb och lägger till det som cron saknar: den kan ta igen en körning som missades medan maskinen var
avstängd, den kan sprida starttiderna slumpmässigt, och den startar aldrig en extra kopia av en
tjänst som fortfarande kör. Inne i PostgreSQL läser tillägget pg_cron samma tidsscheman med fem
fält, och en bakgrundsprocess i databasen håller reda på jobben. Vårt
projekt med en jobbkö i River är ett
exempel: i oktober 2026 räknar sidan upp 20 pg_cron-jobb under kön, som rensar partitioner,
roterar salt och uppdaterar aggregat, alltså underhåll som databasen enligt sidan själv är bättre
lämpad för.
Så ser det ut i praktiken
Ta två jobb: en städning på vardagar och en nattlig dump av en databas. Tabellen sätter först sin
egen miljö, eftersom ett jobb inte ärver inställningarna från ditt inloggningsskal. Raderna med
NAMN=värde och variabeln MAILTO är funktioner i cronie, inte i POSIX.
SHELL=/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=ops@example.com
# minut timme dag månad veckodag 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örsta jobbet läses som ”klockan 03.15, måndag till fredag”. Det andra körs varje natt klockan
02.30, skriver sina utdata och fel till en logg och är inlindat i flock -n, som ger upp direkt i
stället för att vänta när låset redan är taget, så att en dump som drar ut på tiden aldrig får en
tvilling. Det tredje visar det escapade procenttecknet: utan omvänt snedstreck skulle cron klippa av
kommandot vid %.
Håll tabellen i en fil under versionshantering och installera den i sin helhet i stället för att redigera den direkt:
crontab jobs.cron
crontab -lDet andra kommandot visar vad cron faktiskt kommer att läsa. Med flaggan -T i cronie kan du
kontrollera syntaxen i en fil innan du installerar den, och filen måste sluta med en radbrytning.
Samma nattliga dump som systemd-timer kräver två enheter. Tjänsten anger vad som ska köras och timern anger nä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 sparar tidpunkten för den senaste körningen på disk och startar en missad körning
så snart timern är aktiv igen. RandomizedDelaySec= lägger till en slumpmässig fördröjning på upp
till tio minuter, så att en flotta av maskiner med samma fil inte träffar databasservern i samma
sekund. systemd-analyze calendar '*-*-* 02:30:00' visar uttrycket i normaliserad form och när det
utlöses nästa gång, och det är det snabbaste sättet att pröva ett schema innan man litar på det.
Ett schema anger när ett jobb startar, inte om det gjorde sitt arbete. På en av våra värdar med 464 MB vänder dödmansgreppet på det: en timer startar ett skript fyra gånger i timmen, varje gång lite förskjutet på måfå, och skriptet pingar en tjänst utanför maskinen bara när varken minnet eller disken har sjunkit under sin gräns. När pingarna uteblir går larmet.
Var det går fel
Kommandot fungerar i ditt skal men inte i cron. POSIX lovar ett jobb bara HOME, LOGNAME,
PATH och SHELL, och PATH behöver bara hitta standardverktygen. Ingenting från din profil läses
in. Lösningen är att använda absoluta sökvägar eller sätta PATH överst i tabellen, och att testa
jobbet i samma sparsamma miljö.
Fel försvinner. Utdata som inte omdirigeras skickas med e-post. cronie skickar dem till
tabellens ägare, till adressen i MAILTO eller ingenstans alls när MAILTO="". Lösningen är att
omdirigera utdata till en logg som någon läser och, för jobb som spelar roll, att låta jobbet
rapportera att det lyckats till något som klagar när rapporterna uteblir, så som dödmansgreppet ovan
gör.
Ett procenttecken delar kommandot. I kommandofältet blir % en radbrytning; bara den första
raden körs och resten skickas till den som standardindata, så date +%s går sönder. Lösningen är
att escapa tecknet som \% eller att flytta kommandot till ett skript och anropa det.
Två dagfält betyder antingen–eller, inte båda. När både dag i månaden och veckodag är begränsade
körs jobbet varje dag som passar något av dem. POSIX:s eget exempel, 0 0 1,15 * 1, körs den första
och den femtonde i månaden och dessutom varje måndag. Lösningen är att begränsa bara ett av de två
fälten eller att använda en kalender i systemd, där Mon *-*-01..07 09:00 bara passar när både
veckodagen och datumet stämmer: den första måndagen i månaden.
Steg börjar om varje timme. cronie beräknar ett steg bara inom sitt eget fält, så */35 i
minutfältet körs varje timme vid minut 0 och minut 35, inte med 35 minuters mellanrum, och */23 i
timfältet körs vid midnatt och klockan 23. Lösningen är att välja ett steg som går jämnt upp i
intervallet, eller att använda en systemd-timer med OnUnitActiveSec=, som räknar från den senaste
gången tjänsten startades.
Klockan ställs om. cronie dokumenterar att tider som försvinner när klockan ställs fram till
sommartid aldrig matchar, så de jobben körs inte, och att tider som inträffar två gånger när klockan
ställs tillbaka får jobb att köras två gånger. Lösningen är att lägga jobben utanför de timmar då
din tidszon ställs om, eller att sätta CRON_TZ till en zon utan sommartid.
Den sista raden saknar radbrytning. cronie förväntar sig att varje post slutar med en radbrytning; gör den sista inte det betraktar cronie tabellen som åtminstone delvis trasig och skriver en varning till syslog. Lösningen är att alltid avsluta filen med en radbrytning, något som en inställning i editorn eller en kontroll vid granskningen kan garantera.
Körningar överlappar. crontab-formatet har inget fält för vad som ska hända när den förra
körningen fortfarande pågår. En systemd-timer låter en tjänst som fortfarande kör vara i fred. Har
timerns nästa tidpunkt passerat medan tjänsten körde, startar timern tjänsten igen så snart den är
klar, om inte DeferReactivation= är satt; pg_cron låter en ny körning av samma jobb vänta tills
den första är klar. Lösningen är att i vanlig cron använda ett lås, som flock -n i exemplet ovan.
Maskinen var avstängd. En crontab-rad anger ett ögonblick, och formatet kan inte uttrycka ”kör
det senare om ögonblicket har passerat”. Lösningen är att, där systemd styr maskinen, sätta
Persistent=true på en timer med OnCalendar=.
Alla maskiner på en gång. En tabell som kopieras till hundra värdar startar hundra jobb i samma
minut. Lösningen är att använda RandomizedDelaySec= på en systemd-timer, eller i cronie variabeln
RANDOM_DELAY eller ett intervall med tilde som 6~15, som väljer en slumpmässig minut när
tabellen läses.
Ett crontab utan argument tömmer tabellen. Skrivet ensamt väntar kommandot på en ny tabell på
standardindata, och ett filslut (oftast Ctrl-D) ersätter den nuvarande med ingenting. Lösningen är
att trycka på avbrottstangenten i stället och att hålla tabellen i en fil som du installerar med
crontab fil.
Läs mer
- crontab, POSIX.1-2024 — standardens sex fält, standardmiljön, regeln för e-post och motiveringen.
- crontab(5), cronie
— steg,
MAILTO,CRON_TZ,RANDOM_DELAY, sommartid och förbehåll. - systemd.timer(5)
—
OnCalendar=,Persistent=,RandomizedDelaySec=och tjänster som kör. - systemd.time(7) — syntaxen för kalenderhändelser, förkortningarna och hur de valideras.
- flock(1)
— ett lås kring ett kommando, med
-nför att ge upp när låset är taget. - pg_cron — cron-tidsscheman för SQL-jobb, i PostgreSQL som ett tillägg.

