Introduction : pourquoi les files d'attente de tâches en JavaScript ?
\nDans le développement web moderne avec Node.js, on rencontre souvent des tâches qui ne peuvent pas être exécutées instantanément dans le cadre d'une seule requête HTTP. L'envoi de campagnes email, la génération de rapports PDF, le traitement d'images, la synchronisation avec des API externes — toutes ces opérations nécessitent du temps et des ressources. Si elles sont exécutées de manière synchrone, l'utilisateur attendra trop longtemps la réponse et le serveur risque d'être surchargé.
\nLes files d'attente de tâches (Job Queues) résolvent ce problème. Elles permettent de différer l'exécution d'opérations lourdes, de répartir la charge, de garantir un nouveau traitement en cas d'échec et de faire évoluer le système horizontalement. Dans cet article, nous analyserons les aspects pratiques du travail avec les files d'attente en JavaScript (Node.js) : de la théorie à l'écriture de code fonctionnel en utilisant des bibliothèques populaires.
\n\nConcepts de base des files d'attente de tâches
\nAvant de passer au code, il est important de comprendre les éléments clés de toute file d'attente de tâches :
\n- \n
- Job (tâche) — une unité de travail à exécuter. Contient généralement des données (payload) et des métadonnées (priorité, tentatives, statut). \n
- Queue (file d'attente) — une structure de données (souvent basée sur Redis) qui stocke les tâches dans l'ordre d'arrivée. \n
- Worker (travailleur) — un processus ou un thread qui récupère les tâches de la file d'attente et les exécute. \n
- Producer (producteur) — la partie du système qui ajoute des tâches à la file d'attente. \n
- Consumer (consommateur) — synonyme de worker, qui traite les tâches. \n
Dans Node.js, les bibliothèques les plus populaires pour travailler avec les files d'attente sont Bull et Kue. Toutes deux utilisent Redis comme courtier de messages. Bull est plus moderne et performant, Kue est plus simple pour débuter. Dans cet article, nous nous concentrerons sur Bull, comme solution recommandée pour la production.
\n\nImplémentation pratique d'une file d'attente avec Bull
\nInstallation et configuration
\nPour commencer, installez Redis (localement ou via Docker) et ajoutez la bibliothèque au projet :
\nnpm install bull\nL'initialisation de base d'une file d'attente ressemble à ceci :
\nconst Queue = require('bull');\nconst imageQueue = new Queue('traitement d\'images', {\n redis: { host: 'localhost', port: 6379 }\n});\n\nAjout de tâches (Producer)
\nLe producteur ajoute une tâche avec des données et des options :
\napp.post('/upload', async (req, res) => {\n const job = await imageQueue.add({\n imageUrl: req.body.url,\n userId: req.user.id\n }, {\n attempts: 3, // nombre de tentatives en cas d'erreur\n backoff: 5000, // délai entre les tentatives (ms)\n removeOnComplete: true // supprimer la tâche après succès\n });\n res.json({ jobId: job.id });\n});\n\nTraitement des tâches (Worker)
\nLe worker est un processus séparé (ou le même processus, mais asynchrone) qui écoute la file d'attente :
\nimageQueue.process(async (job, done) => {\n try {\n const { imageUrl, userId } = job.data;\n console.log(`Traitement de l'image ${imageUrl} pour l'utilisateur ${userId}`);\n // Votre logique ici : télécharger, redimensionner, sauvegarder\n await processImage(imageUrl);\n done(); // signal de fin réussie\n } catch (error) {\n done(new Error('Erreur de traitement : ' + error.message));\n }\n});\n\nGestion des erreurs et nouvelles tentatives
\nBull réessaie automatiquement la tâche si le worker se termine avec une erreur. Vous pouvez configurer la stratégie de nouvelles tentatives :
\nconst job = await imageQueue.add(data, {\n attempts: 5,\n backoff: { type: 'exponential', delay: 2000 }\n});\nVous pouvez également écouter les événements de la file d'attente pour la surveillance :
\nimageQueue.on('completed', (job, result) => {\n console.log(`Tâche ${job.id} terminée`);\n});\nimageQueue.on('failed', (job, err) => {\n console.error(`Tâche ${job.id} échouée : ${err.mes