---
term: 'Job in background e scheduler di attività'
seoTitle: 'Job in background e scheduler: code, worker, ritentativi'
headline: 'Che cosa sono i job in background e gli scheduler di attività?'
slug: job-in-background
category: backend-compute
shortDefinition: 'Un job in background è un compito che gira fuori dal ciclo della richiesta: accodato dall''app, eseguito dai worker, ritentato in caso di errore.'
relatedTerms:
  - scheduled-cloud-code-cron-jobs
  - cloud-code-serverless-functions
  - pub-sub-pattern
  - webhooks
contrastsWith:
  - scheduled-cloud-code-cron-jobs
aboutTerms:
  - 'Job Queue'
  - 'Worker'
  - 'Dead-Letter Queue'
  - 'Cron'
faq:
  - question: 'Che cos''è un job in background?'
    answer: 'Un compito che l''applicazione esegue fuori dal ciclo richiesta-risposta: il server accoda il lavoro, risponde subito a chi ha fatto la richiesta, e un worker separato lo esegue in modo asincrono – con ritentativi in caso di errore. Tutto ciò che è lento, ritentabile o inutile alla risposta appartiene a quel posto.'
  - question: 'Perché non fare semplicemente il lavoro nell''handler della richiesta?'
    answer: 'Perché il lavoro lento blocca la risposta, immobilizza la capacità del server e va a sbattere contro i timeout del gateway – e se il lavoro va in errore a metà richiesta, l''utente riceve un fallimento anche se una parte è già avvenuta. L''esempio canonico: inviare l''e-mail di benvenuto durante la registrazione, dove un server di posta lento trasforma la creazione dell''account in una rotella che gira.'
  - question: 'Come funziona una coda di job?'
    answer: 'È una lista durevole tra produttori e worker: l''applicazione inserisce un job – un tipo più un piccolo payload – la coda lo persiste, e i worker lo prelevano, lo eseguono e lo confermano. I job non confermati tornano nella coda, ed è da lì che viene l''affidabilità.'
  - question: 'Qual è la differenza tra una coda di job e una coda di messaggi?'
    answer: 'La finalità. Una coda di messaggi sposta dati tra servizi: la consegna è l''obiettivo, e un messaggio può diffondersi verso molti consumatori. Una coda di job esegue lavoro: aggiunge sopra ritentativi, pianificazione, priorità e stato, e ogni job va a esattamente un worker.'
  - question: 'Qual è la differenza tra cron job e job in background?'
    answer: 'Il trigger. Cron è guidato dal tempo – "ogni notte alle 2"; i job in background sono guidati dagli eventi – "quando qualcuno carica un file". I due pattern si combinano: un progetto diffuso affida a cron l''accodamento del batch notturno, mentre i worker lo eseguono con tutta la semantica dei ritentativi.'
  - question: 'Come funzionano i ritentativi dei job?'
    answer: 'I job falliti girano di nuovo automaticamente con un backoff esponenziale – un secondo, poi due, quattro, otto – più un jitter casuale perché mille errori non ritentino tutti nello stesso istante, entro il limite di un numero massimo di tentativi. Il backoff colma i guasti transitori; il tetto impedisce a quelli permanenti di ritentare all''infinito.'
  - question: 'Perché i job in background devono essere idempotenti?'
    answer: 'Perché le code promettono un''esecuzione at-least-once: un worker può andare in crash dopo aver fatto il lavoro ma prima di confermarlo, e il job gira di nuovo. Girare due volte non deve addebitare due volte – chiavi di idempotenza, vincoli di unicità e upsert trasformano i duplicati in no-op.'
  - question: 'Che cos''è una dead letter queue?'
    answer: 'Il posto dove finiscono i job che hanno esaurito i ritentativi: conservati per ispezione, avvisi e rigioco manuale, invece di ritentare all''infinito o sparire in silenzio. I job malformati che non potranno mai riuscire dovrebbero saltare i tentativi e andare direttamente lì.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Sidekiq Best Practices'
    url: 'https://github.com/sidekiq/sidekiq/wiki/Best-Practices'
  - name: 'Celery — Distributed Task Queue'
    url: 'https://docs.celeryq.dev/en/stable/getting-started/introduction.html'
  - name: 'crontab(5) — Linux manual page'
    url: 'https://man7.org/linux/man-pages/man5/crontab.5.html'
  - name: 'Scaling Slack''s Job Queue — Slack Engineering'
    url: 'https://slack.engineering/scaling-slacks-job-queue/'
  - name: 'Job scheduler — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Job_scheduler'
cta:
  title: 'Job senza una coda da gestire'
  text: 'Definisci un Cloud Job su Back4app ed eseguilo su richiesta o secondo una pianificazione dalla dashboard: stato, log e ricorrenza inclusi, senza broker, senza flotta di worker e senza infrastruttura di code da far funzionare.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-13'
translationKey: background-jobs-task-schedulers
---

**Un job in background è un compito che gira fuori dal ciclo della richiesta: accodato dall'app, eseguito dai worker, ritentato in caso di errore.** La linea di demarcazione è il tempo: una risposta deve sembrare istantanea (qualche centinaio di millisecondi) e *deve* battere il timeout del gateway (tipicamente circa 30 secondi), mentre il lavoro reale – e-mail via SMTP, elaborazione di immagini, generazione di report, API di terze parti – richiede da secondi a minuti e merita dei ritentativi. Tutto ciò che sta dalla parte sbagliata di quella linea viene accodato, confermato e svolto altrove; su larga scala è infrastruttura centrale, non idraulica – una grande azienda di messaggistica elabora oltre un miliardo di job al giorno esattamente con questo macchinario.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| L'architettura | Il produttore accoda → la coda persiste → il worker esegue e conferma |
| La linea di demarcazione | Budget di risposta circa 300 ms; tutto ciò che è lento o ritentabile diventa un job |
| Le tre pianificazioni | Immediata · differita ("tra 24 h") · ricorrente (cron) |
| Il contratto di affidabilità | At-least-once + job idempotenti + backoff con jitter + dead letter |
| L'errore silenzioso | Niente dà errore quando un job pianificato non gira – va sorvegliata l'assenza |

## L'anti-pattern che insegna tutto

```js
// ✗ La registrazione che si fa ostaggio di un server di posta
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await sendWelcomeEmail(user);        // SMTP lento? Chi si registra fissa uno spinner.
  res.json(user);                      // SMTP giù? La registrazione dà 500 – ma
});                                    // l'account ESISTE. Il peggio di tutti i mondi.

// ✔ Accodare e rispondere
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await jobs.enqueue('welcomeEmail', { userId: user.id }); // millisecondi
  res.json(user);                      // l'e-mail parte, ritenta e riesce
});                                    // secondo i propri tempi – in modo invisibile
```

Lo stesso principio visto dai due lati di un backend reale – un job che lavora sui dati, e un client che accoda invece di aspettare:

**JavaScript:**

```javascript
// JavaScript — Cloud Code (cloud/main.js)
// A background job: heavy work outside the request cycle
Parse.Cloud.job('sendWeeklyDigest', async (request) => {
  const query = new Parse.Query(Parse.User).equalTo('digestOptIn', true);
  await query.eachBatch(async (users) => {
    for (const user of users) await sendDigest(user); // per-record, resumable
  }, { useMasterKey: true });
  request.message('Digest run complete'); // status visible in the dashboard
});
// Run on demand or on a schedule from the dashboard — no queue to operate
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// The client's rule: never wait on heavy work — enqueue and move on
final export = ParseObject('ExportRequest')
  ..set('user', currentUser)
  ..set('status', 'queued'); // an afterSave trigger starts the work
await export.save(); // returns in milliseconds

// Watch the job's progress like any other data:
final sub = await LiveQuery().client.subscribe(
    QueryBuilder<ParseObject>(ParseObject('ExportRequest'))
      ..whereEqualTo('objectId', export.objectId));
sub.on(LiveQueryEvent.update, (job) {
  if (job.get<String>('status') == 'done') openReport(job.get('fileUrl'));
});
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// The client's rule: never wait on heavy work — enqueue and move on
var export = ExportRequest()
export.status = "queued" // an afterSave trigger starts the work
let saved = try await export.save() // returns in milliseconds

// Watch the job's progress like any other data:
let sub = try await ExportRequest.query("objectId" == saved.id).subscribe()
sub.handleEvent { _, event in
    if case .updated(let job) = event, job.status == "done" {
        openReport(job.fileUrl)
    }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// The client's rule: never wait on heavy work — enqueue and move on
val export = ParseObject("ExportRequest")
export.put("user", ParseUser.getCurrentUser())
export.put("status", "queued") // an afterSave trigger starts the work
export.save() // returns in milliseconds

// Watch the job's progress like any other data:
val q = ParseQuery.getQuery<ParseObject>("ExportRequest")
q.whereEqualTo("objectId", export.objectId)
val sub = ParseLiveQueryClient.Factory.getClient().subscribe(q)
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, job ->
    if (job.getString("status") == "done") openReport(job.getString("fileUrl"))
}
```

## Produttore, coda, worker

```mermaid
flowchart LR
  accTitle: Architettura produttore, coda e worker con ritentativi e dead letter
  accDescr: L'applicazione accoda i job in una coda durevole e risponde subito agli utenti. I worker prelevano i job, li eseguono e li confermano in caso di successo. I job falliti vengono riaccodati con un backoff esponenziale, e quelli che esauriscono i ritentativi passano in una dead letter queue per l'ispezione e il rigioco.
  A["App (produttore)<br/>accoda + risponde subito"] --> Q[("Coda<br/>durevole, più o meno ordinata")]
  S["Scheduler<br/>cron: riaccoda al momento giusto"] --> Q
  Q --> W["Worker<br/>prelevano · eseguono · ack"]
  W -->|"successo"| OK["Fatto"]
  W -.->|"errore"| B["Backoff + jitter<br/>attesa, poi riaccodamento"] -.-> Q
  B -.->|"tentativi esauriti"| DL["Dead letter queue<br/>ispezionare · avvisare · rigiocare"]
```

Tre ruoli, un contratto. Il **produttore** – di solito un handler di richiesta – crea un job: un nome di tipo e un piccolo payload. La **coda** lo persiste; la durabilità è tutto il punto, perché un lavoro che esiste solo nella memoria di un processo in agonia muore con lui. I **worker** prelevano, eseguono e *confermano* (ack); un job sparisce solo dopo la conferma, ed è così che il job di un worker andato in crash sopravvive per girare di nuovo. Il vocabolario che viaggia insieme: enqueue/dequeue, ack, visibility timeout, e la distinzione che vale la pena difendere – una coda di *messaggi* trasporta dati tra servizi (e può diffonderli verso [molti sottoscrittori](/glossary/pub-sub-pattern/)); una coda di *job* esegue lavoro, esattamente una volta per job e per worker, con ritentativi e stato integrati.

## I tre modi di pianificazione – e un'introduzione a cron

Ogni sistema di job implementa gli stessi tre modi temporali: **immediato** (accodato ora, eseguito appena un worker si libera), **differito** (accodato ora, eleggibile in un momento futuro – promemoria, scadenze dei periodi di prova e il meccanismo stesso dei ritentativi) e **ricorrente** (uno scheduler riaccoda secondo un calendario). Le pianificazioni ricorrenti si scrivono quasi sempre con i cinque campi di [cron](https://man7.org/linux/man-pages/man5/crontab.5.html):

```text
┌ minuto (0-59)  ┌ ora (0-23)  ┌ giorno del mese  ┌ mese  ┌ giorno della settimana
0 2 * * *      → ogni giorno alle 02:00
*/15 * * * *   → ogni 15 minuti
0 9 * * 1      → ogni lunedì alle 09:00

Due mine dello scheduler: i passaggi all'ora legale (le 02:30 svaniscono o
avvengono due volte – conviene pianificare in UTC) e la sovrapposizione (un
job che supera il proprio intervallo richiede un lock, altrimenti due copie
elaborano gli stessi dati).
```

## Code di job vs. code di messaggi vs. scheduler

| | Coda di job | Coda di messaggi | Scheduler |
| --- | --- | --- | --- |
| Unità | Un job da eseguire | Un messaggio da consegnare | Un orario di scatto |
| Consumatori | Esattamente un worker | Uno o [molti sottoscrittori](/glossary/pub-sub-pattern/) | I job che accoda |
| Integrati | Ritentativi, stato, priorità, ritardo | Durabilità, routing, fan-out | Calendari, ricorrenza |
| Nomi open source | Sidekiq, Celery, BullMQ | RabbitMQ, Kafka, Redis | cron, Quartz |
| Si combina come | Esegue ciò che gli eventi richiedono | Trasporta tra sistemi | Alimenta la coda al momento giusto |

La combinazione è la risposta a quasi tutti i dibattiti su "quale dei tre?": gli scheduler decidono il *quando*, le code tengono il *che cosa*, i worker fanno il *lavoro* – e un batch notturno è cron che accoda job che i worker eseguono con tutta la semantica dei ritentativi.

## Il contratto di affidabilità

I pezzi si insegnano di solito separatamente; sono un unico contratto. **La coda promette at-least-once** – un worker che va in crash dopo il lavoro ma prima della conferma significa che il job gira di nuovo; è inevitabile, non sciatto. **In cambio si promette idempotenza**: deduplicazione su un ID di job, protezione con vincoli di unicità, scritture in upsert, così la seconda esecuzione è un no-op invece di una seconda fattura. **I ritentativi con backoff esponenziale e jitter** colmano i guasti transitori – 1 s, 2 s, 4 s, con una componente casuale perché mille job che falliscono insieme non ritentino insieme, una cortesia che i [sistemi di terze parti con rate limiting](/glossary/it/rate-limiting-api/) impongono comunque se non viene concessa. **La dead letter queue raccoglie il resto**: dopo il tetto dei tentativi, i job si parcheggiano dove le persone possono ispezionarli, correggerli e rigiocarli – e i job malformati in modo permanente dovrebbero saltare del tutto il teatro dei ritentativi e andare direttamente lì.

## Progettare bene i job

Le regole su cui i framework di coda concordano, messe insieme: **passare ID, non oggetti** – un payload di job che contiene `userId: "u-8fk2"` ricarica lo stato aggiornato al momento dell'esecuzione, mentre un oggetto utente serializzato è già vecchio nell'istante in cui viene accodato; **tenere i payload piccoli** e semplici come JSON, mai segreti; **un job per record** – un job per utente che fallisce ritenta un solo utente, un mega-job ritenta tutti; **rendere riprendibile il lavoro lungo** – spezzarlo in blocchi, salvare il progresso a checkpoint e uscire con grazia sui segnali di arresto a metà blocco; e **dare per scontata la concorrenza** – un giorno due worker elaboreranno job adiacenti che toccano la stessa riga, e quella è una questione di lock a cui si risponde in fase di progetto oppure durante un incidente.

## Sorvegliare la coda

L'errore in background è silenzioso: nessuno vede una pagina di errore quando il job del digest muore. I quattro indicatori che sostituiscono la pagina di errore: la **profondità della coda** (un arretrato che si accumula significa che i worker stanno perdendo), l'**età del job** misurata dall'accodamento al completamento – un job elaborato in 200 ms dopo 40 minuti di attesa è un job da 40 minuti per chi lo aspetta; i **tassi di errore e di dead letter** con avvisi sulla dead letter queue, perché i job parcheggiati e dimenticati sono dati che in silenzio non vengono elaborati; e le **esecuzioni mancate** per il lavoro pianificato – il caso più insidioso, perché una pianificazione che non è mai scattata non ha prodotto nessun errore, nessuna riga di log e nessun job. L'allarme va messo sull'assenza.

## Casi d'uso tipici

- **E-mail e notifiche** – il rinvio canonico: accodare alla registrazione, consegnare con i ritentativi.
- **Elaborazione multimediale** – ridimensionamenti, transcodifiche, anteprime: minuti di CPU che nessuna richiesta dovrebbe attendere.
- **Report ed esportazioni** – generare in background, notificare quando il file è pronto.
- **Sincronizzazione con terze parti** – sincronizzazioni CRM e consegne di [webhook](/glossary/it/webhook/), con backoff contro remoti instabili.
- **Pulizia e manutenzione** – passate di TTL, potatura degli orfani, costruzione dei digest sul cron notturno.

## Quale pattern serve? Matrice decisionale

| Il lavoro assomiglia a | Scegliere |
| --- | --- |
| Attivato da azioni delle persone, volume variabile | Coda di job + worker |
| Calendario fisso, limitato, prevedibile | Job pianificato (cron) |
| Batch notturno su molti record | Cron accoda; i worker eseguono record per record |
| Servizi che si dicono delle cose | [Coda di messaggi / pub-sub](/glossary/pub-sub-pattern/) |
| Lavoro lento che oggi sta dentro un handler di richiesta | Il refactoring qui sopra – accodare e rispondere |
| Deve sopravvivere ai crash e ritentare in sicurezza | Qualsiasi di questi – più il contratto di affidabilità |

## Limiti e trade-off

- **Alla fine, non all'istante.** Il lavoro accodato avviene *dopo* – le interfacce hanno bisogno di stati di attesa, e quel "dopo" ha bisogno di un limite scelto con intenzione.
- **Lo stato esce dal canale principale.** I risultati arrivano via campi di stato, callback o notifiche – la semplicità di richiesta-risposta è spesa, e l'idraulica va messa in bilancio.
- **L'infrastruttura è reale.** Broker, worker e scheduler sono servizi con le proprie modalità di guasto – oppure un problema della piattaforma, che è l'argomento a favore dei job gestiti.
- **I duplicati sono garantiti, prima o poi.** At-least-once è il contratto; ogni job non idempotente è un incidente a orologeria.
- **Le code assorbono il sovraccarico con grazia – con troppa grazia.** Un arretrato che cresce sembra tranquillo fino al momento in cui l'età dei job esplode; gli allarmi su profondità ed età sono il meccanismo di onestà.

## I job in background 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. I job qui sono [Cloud Code](/glossary/it/cloud-code-funzioni-serverless/) con una pianificazione: si definisce `Parse.Cloud.job` – le schede di codice mostrano un job di digest che procede a lotti sugli utenti con `eachBatch`, record per record e riprendibile – e si esegue su richiesta oppure con una ricorrenza in stile cron dalla dashboard, con stato e log nel pannello Jobs; nessun broker da provisionare, nessuna flotta di worker da scalare, nessun servizio di coda da tenere in vita. La metà guidata dagli eventi si compone dalle stesse primitive: un handler di richiesta scrive una riga con `status: "queued"`, un trigger `afterSave` avvia il lavoro, e i client seguono il progresso con le [Live Queries](/glossary/it/live-queries-tempo-reale/) invece di fare polling – il pattern produttore/worker espresso come dati, con il contratto di affidabilità (ID nei payload, handler idempotenti, uno stato su cui mettere un allarme) come disciplina di progetto invece che come infrastruttura.
