Un cron job è un compito che si esegue automaticamente secondo una pianificazione temporale; il Cloud Code pianificato porta l’idea nelle funzioni serverless. La stirpe parte da Unix Version 7, passa per Vixie cron (1987) e arriva agli scheduler delle piattaforme di oggi, e il modello è cambiato appena: un daemon si sveglia ogni minuto, legge una tabella di righe pianificazione + comando – la crontab – e fa scattare ciò che corrisponde. Quello che è cambiato è tutto ciò che sta intorno al modello: dove vive l’orologio, che cosa accade quando un’esecuzione fallisce, e se qualcuno se ne accorge.
Punti chiave
| Domanda | Risposta |
|---|---|
| La sintassi | Cinque campi – minuto · ora · giorno del mese · mese · giorno della settimana |
| Il limite inferiore | Granularità di un minuto; i secondi richiedono un altro scheduler |
| Le insidie | Ora legale: esecuzioni saltate o doppie · la regola dell’OR tra giorno del mese e giorno della settimana |
| Il deficit di affidabilità | Cron classico: nessun ritentativo, nessun recupero, nessun cluster, errori silenziosi |
| La forma moderna | La pianificazione come configurazione di piattaforma su una funzione – orologio, log e ritentativi gestiti |
Cron in una schermata
┌ minuto (0–59) ┌ ora (0–23) ┌ giorno del mese (1–31) ┌ mese ┌ giorno della settimana (0–7)
* * * * * comando
0 2 * * * ogni giorno alle 02:00 */15 * * * * ogni 15 minuti
0 9 * * 1-5 lun-ven alle 09:00 0 6,18 * * * alle 06:00 e alle 18:00
0 0 1,15 * * il 1º e il 15 del mese @daily = 0 0 * * *
@reboot una volta all'avvio @hourly = 0 * * * *
crontab -e modificare la tabella crontab -l elencarla
crontab -ri rimuovere (con conferma – un -r secco la cancella senza chiedere nulla)
L’equivalente moderno – il job nel codice, la pianificazione in una dashboard, il client che si limita a leggere i risultati:
// JavaScript — Cloud Code (cloud/main.js)
// A scheduled job: defined in code, scheduled in the dashboard
Parse.Cloud.job('nightlyReport', async (request) => {
const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
// Idempotent by date key: a rerun overwrites tonight's report, not duplicates
const existing = await new Parse.Query('DailyReport')
.equalTo('runDate', dateKey(new Date()))
.first({ useMasterKey: true });
const report = existing ?? new Parse.Object('DailyReport');
report.set('runDate', dateKey(new Date()));
report.set('summary', await summarizeOrdersSince(since));
await report.save(null, { useMasterKey: true });
request.message('Report written'); // shows in the dashboard's job status
}); // Flutter / Dart — Back4app Flutter SDK
// Clients consume what the schedule produces — no crontab in sight
final query = QueryBuilder<ParseObject>(ParseObject('DailyReport'))
..orderByDescending('runDate')
..setLimit(1);
final latest = (await query.query()).results?.first as ParseObject?;
print(latest?.get<String>('summary'));
// The report exists because a scheduled Cloud Job ran at 02:00 UTC —
// defined in code, scheduled in the dashboard, logged by the platform. // iOS / Swift — Back4app Swift SDK
// Clients consume what the schedule produces — no crontab in sight
let latest = try await DailyReport.query()
.order([.descending("runDate")])
.first()
print(latest.summary ?? "")
// The report exists because a scheduled Cloud Job ran at 02:00 UTC —
// defined in code, scheduled in the dashboard, logged by the platform. // Android / Kotlin — Back4app Android SDK
// Clients consume what the schedule produces — no crontab in sight
val query = ParseQuery.getQuery<ParseObject>("DailyReport")
query.orderByDescending("runDate")
query.limit = 1
val latest = query.find().firstOrNull()
println(latest?.getString("summary"))
// The report exists because a scheduled Cloud Job ran at 02:00 UTC —
// defined in code, scheduled in the dashboard, logged by the platform. Le insidie che la pagina di manuale conosce
Quattro semantiche di crontab(5) che sorprendono quasi tutti. La regola dell’OR: quando sia il giorno del mese sia il giorno della settimana sono vincolati, il job scatta appena uno dei due corrisponde – 0 0 13 * 5 gira il 13 del mese e ogni venerdì, non solo il venerdì 13. L’ora legale, alla lettera: i job pianificati nell‘“ora mancante” del passaggio all’ora legale non girano mai; gli orari che si presentano due volte al ritorno all’ora solare girano due volte – conviene pianificare in UTC e tenere il lavoro critico fuori dalle ore piccole locali. I passi ripartono da zero ai confini del campo: */90 nel campo dei minuti non può significare “ogni 90 minuti” – il contatore riparte a ogni ora; gli intervalli davvero irregolari richiedono un vero scheduler. Il limite del minuto: il daemon scorre la tabella una volta al minuto; tutto ciò che è più fine è compito di un altro strumento.
Il deficit di affidabilità
Il cron classico è uno scheduler, non un sistema di affidabilità, e il deficit ha una forma precisa: nessun ritentativo (un’esecuzione fallita resta fallita); nessun recupero (una macchina in sospensione alle 02:00 salta l’esecuzione – anacron e l’opzione di persistenza dei timer systemd esistono proprio per questo); nessuna risposta per il cluster (due server con la stessa crontab eseguono tutto in doppio; un solo server è un single point of failure); l’errore silenzioso (l’output viene spedito per posta a un account locale che nessuno legge). Gli scheduler moderni rispondono a ogni mancanza con una politica dal nome preciso: le politiche di misfire (il fire-now contro lo skip di Quartz), le politiche di concorrenza (l’allow/forbid/replace di Kubernetes per le esecuzioni che si sovrappongono) e una semantica di salto basata su una scadenza – documentando onestamente che la pianificazione distribuita è approssimativamente una volta sola: un’esecuzione può, di tanto in tanto, risultare doppia oppure non scattare affatto. Da qui la disciplina che i due mondi condividono: i job pianificati devono essere idempotenti – con una chiave sul proprio periodo (il report delle schede di codice, con chiave la data) perché una nuova esecuzione sovrascriva invece di duplicare, e perché un’esecuzione mancata si recuperi girando in ritardo.
Cron classico vs. timer systemd vs. scheduler distribuiti vs. funzioni pianificate
| Cron classico | Timer systemd | Distribuito (stile Quartz/K8s) | Funzioni cloud pianificate | |
|---|---|---|---|---|
| Vive in | La crontab di una macchina | Una macchina, file di unità | Un cluster | La configurazione della piattaforma, su una funzione |
| Recupero | Nessuno (anacron lo innesta) | Persistent=true | Politiche di misfire | Politica della piattaforma |
| Sovrapposizione | Avvia un’altra copia | Serializzato per unità | allow / forbid / replace | Politica della piattaforma |
| Ritentativi | Nessuno | Regole di riavvio del servizio | Configurabili | Integrati |
| Visibilità degli errori | Posta locale, mai letta | journald | Oggetti di stato dei job | Stato + log nella dashboard |
| Server da tenere in vita | Sì – ed è il single point of failure | Sì | Il cluster | No |
Sorvegliare le pianificazioni
L’errore pianificato è l’errore più silenzioso dell’informatica: un job che non è mai scattato non emette niente – nessuna eccezione, nessuna riga di log, nessuna e-mail – perché non è girato niente. Il pattern che risolve la cosa inverte l’allarme: il monitoring con heartbeat – il job fa un ping a una URL quando termina con successo, il monitor attende quel ping entro un periodo di grazia, ed è l’assenza a far scattare l’avviso. Va abbinato all’igiene elementare che il cron classico non ha mai avuto: la durata delle esecuzioni tracciata nel tempo (il report che il mese scorso prendeva 4 minuti e stasera 40 sta dicendo qualcosa), l’output catturato in log veri invece che nella posta locale, e l’inventario delle pianificazioni documentato – perché una crontab sparsa su cinque server è il modo in cui le organizzazioni scoprono job di cui avevano dimenticato l’esistenza.
Casi d’uso tipici
- Report e digest – l’aggregazione notturna abbozzata nelle schede di codice: aggregare, scrivere, notificare.
- Pulizia e scadenze – passate di TTL, potatura degli orfani, scadenza di sessioni e token.
- Sincronizzazione dei dati – recuperi periodici da sistemi di terze parti che non offrono webhook.
- Promemoria e riattivazione – invii legati al tempo: fine del periodo di prova, carrelli abbandonati, avvisi di rinnovo.
- Integrità e riconciliazione – l’audit pianificato che recupera ciò che i percorsi a eventi hanno mancato.
Quale scheduler scegliere? Matrice decisionale
| Situazione | Scegliere |
|---|---|
| Una sola macchina Linux già in gestione | Il cron classico – con lock e un heartbeat |
| Macchine portatili o accese a intermittenza | anacron / timer systemd con persistenza |
| Un cluster già in funzione | Il suo controller nativo di job pianificati |
| Backend di un’app su un BaaS | Cloud Job pianificati – senza server, log inclusi |
| Intervalli sotto il minuto o irregolari | Un vero scheduler o una coda, non aritmetica di crontab |
| Lavoro a eventi etichettato per errore come pianificato | La coda di job – cron si limita ad alimentarla |
Limiti e trade-off
- Un trigger temporale dice quando, non se. Una pianificazione scatta che ci sia lavoro o no; i trigger a eventi e le code si adattano al lavoro che arriva in modo irregolare.
- L‘“approssimativamente una volta” è il contratto onesto. Anche gli scheduler gestiti a volte raddoppiano o saltano un’esecuzione; l’idempotenza è sempre responsabilità del job.
- Il fuso orario è una decisione di politica. Le pianificazioni in UTC sopravvivono all’ora legale; quelle in ora locale servono le persone – la scelta va fatta con intenzione e documentata ad alta voce.
- La frequenza ha un limite inferiore e un prezzo. Il minuto per il cron classico, limiti dipendenti dalla piattaforma altrove; un polling via cron ad alta frequenza di solito è una coda travestita da orologio.
- Le pianificazioni si accumulano in silenzio. Ogni job notturno “temporaneo” è permanente finché non viene inventariato; la dashboard che li elenca tutti è una feature sottovalutata.
Il Cloud Code pianificato su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. Qui la pianificazione rende concreta la colonna moderna della tabella di confronto: si definisce Parse.Cloud.job in Cloud Code – il report notturno delle schede di codice, idempotente grazie alla chiave sulla data, con accesso master key per l’aggregazione su più utenti – e poi si pianifica nel pannello Background Jobs della dashboard: nome del job, ora di avvio, ricorrenza, senza sintassi crontab e senza un server su cui quella crontab dovrebbe vivere. Esecuzioni, stati ed errori finiscono nei log del server e nel pannello dei job – la colonna “visibilità degli errori” risolta per impostazione predefinita – e le discipline con cui questo articolo si chiude restano in mano a chi sviluppa, per progetto: dare ai job una chiave sul loro periodo, tenerli idempotenti e lasciare che un heartbeat confermi che l’orologio della piattaforma e la logica si sono trovati d’accordo stasera, come ogni sera.
Domande frequenti
Che cos'è un cron job?
Un compito pianificato per girare automaticamente a orari o intervalli fissi – classicamente dal daemon cron dei sistemi Unix, che legge una crontab, e per estensione qualsiasi job attivato dall'orologio, su qualunque piattaforma. Il nome viene da chronos, il tempo in greco.
Che cosa significano i cinque campi di un'espressione cron?
Minuto (0–59), ora (0–23), giorno del mese (1–31), mese (1–12), giorno della settimana (0–7, dove 0 e 7 indicano entrambi la domenica), seguiti dal comando. L'asterisco significa tutti i valori; la virgola elenca, il trattino definisce un intervallo, la barra indica un passo.
Che cosa succede se la macchina è spenta all'ora prevista?
Il cron classico salta semplicemente l'esecuzione: non esiste alcun recupero. È per questo che anacron esiste per le macchine accese a intermittenza, che i timer systemd offrono un'opzione di persistenza e che gli scheduler moderni fanno della politica di recupero un'impostazione esplicita invece di una sorpresa.
Come gestisce cron l'ora legale?
Male, per impostazione predefinita: secondo il manuale stesso, i job pianificati nell'"ora mancante" del passaggio all'ora legale non girano mai, e gli orari che si presentano due volte al ritorno all'ora solare girano due volte. Il consiglio di sempre: pianificare in UTC e tenere i job critici fuori dalla fascia locale 00:00–03:00.
Che cosa succede se un job gira ancora quando parte l'esecuzione successiva?
Il cron classico avvia allegramente una seconda copia, e poi una terza. La sovrapposizione richiede una risposta esplicita: un file di lock che fa saltare l'esecuzione in ritardo, oppure le politiche formalizzate degli scheduler moderni – consentire, vietare o sostituire l'istanza in corso.
Come si fa a sapere che un cron job è fallito?
Per impostazione predefinita non si sa: l'output finisce in una casella di posta locale che nessuno legge, e una pianificazione che non scatta mai non produce nessun errore, perché non è girato niente. Il pattern che risolve la cosa: il monitoring con heartbeat – il job fa un ping a una URL in caso di successo, ed è l'assenza del ping a far scattare l'allarme.
Cron può eseguire un job più di una volta al minuto?
No: il minuto è il limite inferiore del cron classico; il daemon si sveglia, scorre la tabella e scatta minuto per minuto. Una granularità al secondo richiede un altro scheduler: espressioni a sei campi in stile Quartz, un ciclo dentro un servizio, oppure una coda di eventi invece di un orologio.
Serve un server per eseguire i cron job?
Non più. Le piattaforme serverless agganciano una pianificazione direttamente a una funzione: la piattaforma possiede l'orologio, fa scattare il job, registra log e stato ed esegue i ritentativi secondo la politica definita – una pianificazione come configurazione invece di un file su una macchina da tenere in vita.