Chapitre 1 · Leçon 1
Jobs background, retries et priorités
Section 1
Step 1
Certaines opérations sont trop longues pour une requête HTTP synchrone (envoi d'email, génération PDF, redimensionnement d'image). Les queues permettent de répondre immédiatement au client et de traiter en arrière-plan.
snippet.typescript
1// Sans queue — l'utilisateur attend tout
2app.post("/api/register", async (req, res) => {
3 const user = await createUser(req.body);
4 await sendWelcomeEmail(user.email); // 2-3 secondes
5 await generateAvatar(user.id); // 5 secondes
6 await indexUserInSearch(user); // 1 seconde
7 await notifyAdmins(user); // 1 seconde
8 // Total : ~9 secondes d'attente ! ❌
9 res.status(201).json({ user });
10});
11
12// ─── Avec BullMQ — réponse immédiate, traitement async ────────
13import { Queue, Worker, Job } from "bullmq";
14import { createClient } from "redis";
15
16const connection = createClient({ url: process.env.REDIS_URL });
17
18// Définir les queues
19export const emailQueue = new Queue("emails", { connection });
20export const mediaQueue = new Queue("media", { connection });
21export const searchQueue = new Queue("search", { connection });
22
23// Route — réponse en < 100ms
24app.post("/api/register", async (req, res) => {
25 const user = await createUser(req.body);
26
27 // Ajouter les jobs en queue — non bloquant
28 await emailQueue.add("welcome-email", {
29 userId: user.id,
30 email: user.email,
31 firstName: user.firstName,
32 }, {
33 attempts: 3, // 3 tentatives si erreur
34 backoff: { type: "exponential", delay: 1000 }, // 1s, 2s, 4s
35 priority: 1, // Haute priorité
36 });
37
38 await mediaQueue.add("generate-avatar", { userId: user.id }, {
39 delay: 2000, // Démarrer dans 2 secondes
40 removeOnComplete: { count: 100 }, // Garder 100 jobs complétés
41 removeOnFail: { count: 1000 },
42 });
43
44 res.status(201).json({ user }); // Réponse immédiate ✅
45});Step 2
Un Worker consomme les jobs d'une queue. Il peut y avoir plusieurs workers en parallèle (concurrence), sur plusieurs machines.