Pourquoi Go est-il le langage idéal pour les files d'attente et les tâches d'arrière-plan ?
\n\nSi vous avez déjà écrit un backend en Python ou Node.js, vous avez sûrement rencontré ce problème : l'application traite une requête, mais en même temps, elle doit envoyer un email, générer un rapport ou traiter un fichier téléchargé. Si vous le faites de manière synchrone, l'utilisateur attend. Si vous le faites dans un thread séparé, vous commencez à danser avec les verrous et les conditions de concurrence.
\n\nGo résout ce problème de manière élégante et native. Les goroutines et les canaux (channels) sont des mécanismes de concurrence intégrés qui rendent le développement de files d'attente et de tâches d'arrière-plan en Go simple et sûr. Dans cet article, nous verrons comment organiser le traitement d'arrière-plan en utilisant à la fois la bibliothèque standard et des outils populaires comme RabbitMQ. Vous verrez des exemples de code concrets que vous pouvez appliquer immédiatement dans votre projet.
\n\nLes bases : goroutines et canaux
\n\nAvant de plonger dans les files d'attente, rappelons les bases. Une goroutine est un fil d'exécution léger qui est lancé avec le mot-clé go. Un canal est un « pipeline » typé à travers lequel les goroutines communiquent entre elles.
Exemple simple : envoi d'email asynchrone
\n\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc sendEmail(email string) {\n time.Sleep(2 * time.Second) // simulation d'une opération longue\n fmt.Println("Email sent to", email)\n}\n\nfunc main() {\n fmt.Println("Start")\n go sendEmail("user@example.com") // lancement en arrière-plan\n fmt.Println("Continue processing...")\n time.Sleep(3 * time.Second) // attend la fin de la goroutine\n}\n\nIci, sendEmail s'exécute en arrière-plan, tandis que le flux principal n'est pas bloqué. Mais que faire si vous devez traiter 1000 emails ? Lancer 1000 goroutines n'est pas une bonne idée : elles commenceront à se faire concurrence pour les ressources. C'est là que les canaux et le motif Worker Pool viennent à la rescousse.
Le motif Worker Pool en Go
\n\nLe Worker Pool est une approche classique pour organiser les files d'attente et les tâches d'arrière-plan en Go. Vous avez un nombre fixe de workers (goroutines) qui écoutent un seul canal de tâches. Les tâches arrivent du flux principal ou d'un gestionnaire HTTP.
\n\nImplémentation du Worker Pool
\n\npackage main\n\nimport (\n "fmt"\n "sync"\n "time"\n)\n\ntype Task struct {\n ID int\n Data string\n}\n\nfunc worker(id int, tasks <-chan Task, wg *sync.WaitGroup) {\n defer wg.Done()\n for task := range tasks {\n fmt.Printf("Worker %d processing task %d: %s\\n", id, task.ID, task.Data)\n time.Sleep(1 * time.Second) // simulation de travail\n }\n}\n\nfunc main() {\n const numWorkers = 3\n tasks := make(chan Task, 10) // canal tamponné\n\n var wg sync.WaitGroup\n\n // Lancement des workers\n for i := 1; i <= numWorkers; i++ {\n wg.Add(1)\n go worker(i, tasks, &wg)\n }\n\n // Envoi des tâches\n for i := 1; i <= 10; i++ {\n tasks <- Task{ID: i, Data: fmt.Sprintf("Task %d", i)}\n }\n close(tasks) // fermeture du canal pour que les workers se terminent\n\n wg.Wait()\n fmt.Println("All tasks completed")\n}\n\nCe code crée 3 workers qui traitent 10 tâches. Le canal tamponné permet d'envoyer des tâches sans blocage, tant que le tampon n'est pas plein. Ce motif est parfait pour les tâches d'arrière-plan en Golang dans les applications web : vous recevez une requête, placez la tâche dans le canal et répondez immédiatement à l'utilisateur.
\n\nFiles d'attente en Go avec RabbitMQ
\n\nPour les systèmes distribués, les canaux en mémoire ne suffisent pas : vous avez besoin d'un stockage externe de files d'attente. RabbitMQ est l'un des courtiers de messages les plus populaires. Voyons comment le connecter à une application Go.
\n\nInstallation et connexion
\n\nCommencez par installer la bibliothèque amqp :
go get github.com/rabbitmq/amqp091-go\n\n