Ogni server ha compiti da svolgere a intervalli regolari: il backup notturno, la pulizia dei file temporanei, il rinnovo di un certificato, l'invio di un report settimanale. Su Linux gli strumenti per farlo sono due: il classico cron, presente da decenni, e i timer di systemd, più recenti e più ricchi. Entrambi funzionano bene, a patto di conoscere le loro trappole.
Cron: la sintassi
Cron legge le crontab, file in cui ogni riga descrive un lavoro con cinque campi temporali seguiti dal comando:
# minuto ora giorno-mese mese giorno-settimana comando
30 2 * * * /usr/local/bin/backup.sh
0 */6 * * * /usr/local/bin/sincronizza.sh
15 8 * * 1 /usr/local/bin/report-settimanale.sh
La prima riga esegue il backup ogni giorno alle 2:30; la seconda ogni sei ore allo scoccare dell'ora; la terza ogni lunedì alle 8:15. Il comando crontab -e modifica la crontab dell'utente corrente, mentre i file in /etc/cron.d/ permettono di definire lavori di sistema indicando anche l'utente con cui eseguirli.
Le trappole di cron
L'ambiente è quasi vuoto
Il problema più comune è un lavoro che funziona lanciato a mano e fallisce da cron. La ragione è quasi sempre l'ambiente: cron esegue i comandi con un PATH minimo e senza le variabili che la tua shell carica all'accesso. La soluzione è usare percorsi assoluti per programmi e file, oppure definire le variabili necessarie all'inizio dello script.
L'output si perde
Per impostazione predefinita cron tenta di inviare per email l'output dei comandi. Su un server senza posta configurata, quell'output finisce nel nulla, compresi i messaggi di errore. È buona pratica reindirizzare l'output in un file di registro o, meglio, nel registro di sistema.
Il carattere percento
Nella crontab il simbolo % ha un significato speciale e va preceduto da una barra rovesciata. Un comando come date +%Y-%m-%d scritto direttamente nella crontab non fa ciò che ti aspetti. Spostare la logica in uno script elimina il problema.
Lavori persi a server spento
Se il server è spento all'ora prevista, cron non recupera il lavoro mancato. Su un portatile o su una macchina che si riavvia spesso, un backup notturno può saltare per giorni senza che nessuno se ne accorga.
I timer di systemd
Sulle distribuzioni che usano systemd si può pianificare un lavoro con due file: un servizio, che descrive cosa eseguire, e un timer, che descrive quando.
# /etc/systemd/system/backup.service
[Unit]
Description=Backup notturno
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Esegue il backup ogni notte
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=10min
[Install]
WantedBy=timers.target
Si attiva con systemctl enable --now backup.timer e si controlla con systemctl list-timers, che mostra l'ultima e la prossima esecuzione di ogni timer.
Cosa offrono in più
- Persistent=true recupera i lavori persi: se il server era spento all'ora prevista, il lavoro parte appena si riaccende.
- Registri integrati: tutto l'output finisce nel journal, consultabile con
journalctl -u backup.service. - Nessuna sovrapposizione: se l'esecuzione precedente è ancora in corso, il timer non ne avvia una seconda dello stesso servizio.
- Ritardo casuale:
RandomizedDelaySecdistribuisce l'avvio, utile quando molti server colpirebbero lo stesso servizio nello stesso istante. - Limiti di risorse: si possono limitare CPU e memoria del lavoro con le normali opzioni di systemd.
- Dipendenze: un lavoro può partire solo dopo che la rete o un disco sono disponibili.
Confronto rapido
| Aspetto | cron | systemd timer |
|---|---|---|
| Semplicità di scrittura | Una riga | Due file |
| Lavori persi a macchina spenta | Non recuperati | Recuperabili |
| Registri | Da configurare | Integrati nel journal |
| Esecuzioni sovrapposte | Possibili | Evitate per lo stesso servizio |
| Portabilità | Quasi ovunque | Solo sistemi con systemd |
Buone pratiche per qualsiasi strumento
Script robusti
Inizia gli script di shell con set -euo pipefail, così che si fermino al primo errore invece di proseguire con dati incompleti. Uno script di backup che continua dopo un errore può sovrascrivere una copia valida con una vuota.
Evitare le sovrapposizioni con cron
Se usi cron per un lavoro che può durare più dell'intervallo, proteggilo con flock, che impedisce l'avvio di una seconda copia finché la prima non ha finito:
*/10 * * * * flock -n /tmp/sync.lock /usr/local/bin/sincronizza.sh
Sapere quando qualcosa non parte
Il silenzio è il nemico dei lavori pianificati: un backup che fallisce senza avvisare è peggio di nessun backup, perché dà una falsa sicurezza. Una tecnica efficace è il controllo inverso: al termine positivo, lo script contatta un servizio di monitoraggio. Se il segnale non arriva entro l'orario previsto, il servizio invia un avviso. Così si scoprono anche i lavori che non sono partiti affatto, non solo quelli falliti.
Attenzione al fuso orario
Gli orari si riferiscono al fuso del server. Con l'ora legale, un lavoro pianificato in un orario che salta o si ripete durante il cambio può non partire o partire due volte. Molti amministratori impostano i server in UTC per evitare sorprese.
In sintesi
- Cron è semplice e universale; i timer di systemd offrono recupero dei lavori persi, registri e protezione dalle sovrapposizioni.
- In cron usa percorsi assoluti, reindirizza l'output e sposta la logica in script.
- Con systemd,
Persistent=trueejournalctlrisolvono due dei problemi più comuni. - Scrivi script che si fermano al primo errore ed evita esecuzioni sovrapposte.
- Usa un controllo inverso per sapere quando un lavoro fallisce o non parte affatto.