Node04 maggio 2026 · 6 min
Queue e job con Node: lezioni da cinque anni di produzione
Retry, idempotenza e osservabilità: gli errori che pago ancora oggi.
Le code sono facili da avviare e difficili da gestire bene. Dopo cinque anni con BullMQ in produzione, questi sono i principi che non negozio più.
L’idempotenza non è opzionale
Un job può girare due volte. Sempre. Progetto ogni handler perché rieseguirlo sia innocuo.
import { Worker } from "bullmq";
new Worker("email", async (job) => { const { userId, templateId } = job.data;
// Chiave di idempotenza: se già inviata, esco senza rifare nulla const key = `sent:${userId}:${templateId}`; if (await redis.get(key)) return;
await mailer.send(userId, templateId); await redis.set(key, "1", "EX", 86_400);});Retry con backoff esponenziale
Fallire va bene, ritentare subito no: sovraccarica il sistema già in difficoltà.
await queue.add("email", payload, { attempts: 5, backoff: { type: "exponential", delay: 2_000 }, removeOnComplete: 1_000,});Osservabilità prima di tutto
Il consiglio che darei a me stesso di cinque anni fa:
# Un job che fallisce in silenzio è un incidente che scopri dal clientenpm run queue:metrics -- --queue email --window 1hMetti le metriche di coda (job attivi, falliti, latenza) su una dashboard prima di andare in produzione, non dopo il primo disastro.