Files d'attente et tâches d'arrière-plan en Rust : écrivez un worker asynchrone en une heure
\n\nAvez-vous déjà remarqué que votre service web « ralentit » parfois lorsqu'un utilisateur clique sur le bouton « Envoyer » ? Le plus souvent, la faute en revient aux opérations lourdes qui s'exécutent directement pendant le traitement de la requête. Envoi d'e-mails, génération de PDF, traitement d'images, intégration avec des API externes — tout cela doit vivre sa propre vie, sans bloquer la réponse à l'utilisateur. La solution : les files d'attente et les tâches d'arrière-plan.
\n\nEt si vous avez l'habitude de résoudre ce problème en Python avec Celery ou RQ, Rust vous réserve une surprise. Rust n'est pas seulement rapide — il offre un contrôle unique sur la mémoire et les threads, permettant d'écrire des workers ultra-efficaces qui consomment un minimum de ressources. Dans cet article, nous allons voir comment implémenter des files d'attente et des tâches d'arrière-plan en Rust, en utilisant des bibliothèques et des approches modernes. Vous apprendrez à construire un système de traitement de tâches fiable qui ne s'effondrera pas sous la charge.
\n\nPourquoi Rust pour les tâches d'arrière-plan ? Trois avantages non évidents
\n\nAvant de plonger dans le code, voyons pourquoi utiliser Rust pour les files d'attente alors qu'il existe des solutions Python éprouvées.
\n\n- \n
- Performances sans GC (ramasse-miettes). Les workers Python peuvent « se figer » lors des pauses du ramasse-miettes. Rust n'a pas ce problème — vous contrôlez chaque octet de mémoire. C'est crucial pour les systèmes à forte charge où chaque milliseconde compte. \n
- Asynchrone « prêt à l'emploi ». Rust avec
tokioouasync-stdpermet de traiter des milliers de connexions simultanées sur un seul thread. Vous pouvez lancer des centaines de workers sans craindre un débordement de mémoire. \n - Fiabilité. Le système de possession (ownership) de Rust garantit que vous n'aurez pas de condition de concurrence (data race) dans un worker d'arrière-plan. Les erreurs sont traitées explicitement — pas d'exceptions cachées. \n
Maintenant que nous avons compris le « pourquoi », passons au « comment ».
\n\nChoisir un courtier de messages : RabbitMQ vs Redis vs NATS
\n\nUne file d'attente de tâches n'est pas qu'une simple liste. C'est un courtier de messages qui stocke les tâches et les distribue entre les workers. Dans l'écosystème Rust, il existe des crates pour tous les courtiers populaires.
\n\nRabbitMQ + lapin : le classique du monde des files d'attente
\n\nRabbitMQ est un monstre fiable pour les tâches d'entreprise. La crate lapin fournit une API asynchrone propre. Il est idéal si vous avez besoin de routage de messages, de garanties de livraison et de topologies complexes.
Redis + fred : simplicité et rapidité
\n\nRedis est un couteau suisse. Avec fred (client Redis asynchrone), vous pouvez créer une file d'attente via des listes (BLPOP) ou Pub/Sub. Redis est parfait pour les scénarios simples : « tâche envoyée — résultat obtenu ».
NATS + async-nats : un courtier léger
\n\nNATS est un courtier cloud avec une latence minimale. Si vous devez traiter des millions de messages par seconde sur de petites instances, NATS est votre choix.
\n\nDans cet article, nous nous concentrerons sur RabbitMQ, car il offre le contrôle le plus complet. Mais les principes seront les mêmes pour n'importe quel courtier.
\n\nÉcrire une file d'attente en Rust : exemple pas à pas
\n\nCréons un système simple : un générateur de tâches (producer) et un worker (consumer). Nous traiterons des tâches d'envoi d'e-mails.
\n\nÉtape 1 : Configuration du projet et des dépendances
\n\nCréez un nouveau projet :
\n\ncargo new rust_queue_demo\ncd rust_queue_demo\n\nAjoutez les dépendances dans Cargo.toml :
[dependencies]\ntokio = { version = "1", features = ["full"] }\nlapin = "2.4"\nserde = { version = "1", features = ["derive"] }\nserde_json = "1"\ntracing = "0.1"\ntracing-subscriber = "0.3"\nanyhow = "1"\n\nNous utilisons tokio comme runtime asynchrone, lapin pour RabbitMQ, serde pour la sérialisation des tâches et tracing pour la journalisation.