Échanger des messages avec des files d’attente Azure Service Bus (Go)
Dans ce tutoriel, vous apprendrez comment envoyer et recevoir des messages de files d’attente Azure Service Bus en utilisant le langage de programmation Go.
Azure Service Bus est un répartiteur de messages d’entreprise complètement managé, avec des files d’attente de messages et des fonctionnalités de publication/abonnement. Service Bus est utilisé pour dissocier les applications et les services les uns des autres, en fournissant un moyen de transport distribué, fiable et haute performance pour les messages.
Le package azservicebus d’Azure SDK pour Go vous permet d’envoyer et de recevoir des messages à partir d’Azure Service Bus et à l’aide du langage de programmation Go.
À la fin de ce tutoriel, vous serez en mesure d’envoyer un message unique ou un lot de messages à une file d’attente, ainsi que de recevoir des messages et des messages restés lettres mortes qui n’ont pas été traités.
Prérequis
- Un abonnement Azure. Vous pouvez activer les avantages de votre abonnement Visual Studio ou MSDN ou vous inscrire pour créer un compte gratuit.
- Si vous n’avez pas de file d’attente à utiliser, suivez les étapes de l’article Utiliser le portail Azure pour créer une file d’attente Service Bus pour créer une file d’attente.
- Version 1.18 ou une version ultérieure de Go
Créer un exemple d'application
Commencez par créer un nouveau module Go.
Créez un répertoire pour le module nommé
service-bus-go-how-to-use-queues
.Dans le répertoire
azservicebus
, initialisez le module et installez les packages requis.go mod init service-bus-go-how-to-use-queues go get github.com/Azure/azure-sdk-for-go/sdk/azidentity go get github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus
Créez un nouveau fichier appelé
main.go
.
Authentifier et créer un client
Dans le fichier main.go
, créez une fonction nommée GetClient
et ajoutez le code suivant :
func GetClient() *azservicebus.Client {
namespace, ok := os.LookupEnv("AZURE_SERVICEBUS_HOSTNAME") //ex: myservicebus.servicebus.windows.net
if !ok {
panic("AZURE_SERVICEBUS_HOSTNAME environment variable not found")
}
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
panic(err)
}
client, err := azservicebus.NewClient(namespace, cred, nil)
if err != nil {
panic(err)
}
return client
}
La fonction GetClient
retourne un nouvel objet azservicebus.Client
créé en utilisant des informations d’identification et un espace de noms Azure Service Bus. L’espace de noms est fourni par la variable d’environnement AZURE_SERVICEBUS_HOSTNAME
. Quant aux informations d’identification, elles sont créées à l’aide de la fonction azidentity.NewDefaultAzureCredential
.
Pour le développement local, le DefaultAzureCredential
a utilisé le jeton d’accès d’Azure CLI, qui peut être créé en exécutant la commande az login
pour s’authentifier auprès d’Azure.
Conseil
Pour vous authentifier à l’aide d’une chaîne de connexion, utilisez la fonction NewClientFromConnectionString.
Envoi de messages à une file d'attente
Dans le fichier main.go
, créez une fonction nommée SendMessage
et ajoutez le code suivant :
func SendMessage(message string, client *azservicebus.Client) {
sender, err := client.NewSender("myqueue", nil)
if err != nil {
panic(err)
}
defer sender.Close(context.TODO())
sbMessage := &azservicebus.Message{
Body: []byte(message),
}
err = sender.SendMessage(context.TODO(), sbMessage, nil)
if err != nil {
panic(err)
}
}
SendMessage
accepte deux paramètres : une chaîne de message et un objet azservicebus.Client
. Il crée ensuite un objet azservicebus.Sender
et envoie le message à la file d’attente. Pour envoyer des messages en bloc, ajoutez la fonction SendMessageBatch
à votre fichier main.go
.
func SendMessageBatch(messages []string, client *azservicebus.Client) {
sender, err := client.NewSender("myqueue", nil)
if err != nil {
panic(err)
}
defer sender.Close(context.TODO())
batch, err := sender.NewMessageBatch(context.TODO(), nil)
if err != nil {
panic(err)
}
for _, message := range messages {
if err := batch.AddMessage(&azservicebus.Message{Body: []byte(message)}, nil); err != nil {
panic(err)
}
}
if err := sender.SendMessageBatch(context.TODO(), batch, nil); err != nil {
panic(err)
}
}
SendMessageBatch
accepte deux paramètres : une tranche de messages et un objet azservicebus.Client
. Il crée ensuite un objet azservicebus.Sender
et envoie les messages à la file d’attente.
Réception des messages d'une file d'attente
Une fois que vous avez envoyé des messages à la file d’attente, vous pouvez les recevoir avec le type azservicebus.Receiver
. Pour recevoir les messages d’une file d’attente, ajoutez la fonction GetMessage
à votre fichier main.go
.
func GetMessage(count int, client *azservicebus.Client) {
receiver, err := client.NewReceiverForQueue("myqueue", nil) //Change myqueue to env var
if err != nil {
panic(err)
}
defer receiver.Close(context.TODO())
messages, err := receiver.ReceiveMessages(context.TODO(), count, nil)
if err != nil {
panic(err)
}
for _, message := range messages {
body := message.Body
fmt.Printf("%s\n", string(body))
err = receiver.CompleteMessage(context.TODO(), message, nil)
if err != nil {
panic(err)
}
}
}
GetMessage
accepte un objet azservicebus.Client
et crée un objet azservicebus.Receiver
. Il reçoit ensuite les messages de la file d’attente. La fonction Receiver.ReceiveMessages
accepte deux paramètres : un contexte et le nombre de messages à recevoir. La fonction Receiver.ReceiveMessages
retourne une tranche d’objets azservicebus.ReceivedMessage
.
Ensuite, une boucle for
effectue une itération dans les messages et imprime le corps du message. Après quoi, la fonction CompleteMessage
est appelée pour terminer le traitement du message et le supprimer de la file d’attente.
Les messages qui dépassent les limites de longueur sont envoyés à une file d’attente des messages non valides et ceux qui ne sont pas traités correctement peuvent être envoyés à la file d’attente de lettres mortes. Pour envoyer des messages à la file d’attente de lettres mortes, ajoutez la fonction SendDeadLetterMessage
à votre fichier main.go
.
func DeadLetterMessage(client *azservicebus.Client) {
deadLetterOptions := &azservicebus.DeadLetterOptions{
ErrorDescription: to.Ptr("exampleErrorDescription"),
Reason: to.Ptr("exampleReason"),
}
receiver, err := client.NewReceiverForQueue("myqueue", nil)
if err != nil {
panic(err)
}
defer receiver.Close(context.TODO())
messages, err := receiver.ReceiveMessages(context.TODO(), 1, nil)
if err != nil {
panic(err)
}
if len(messages) == 1 {
err := receiver.DeadLetterMessage(context.TODO(), messages[0], deadLetterOptions)
if err != nil {
panic(err)
}
}
}
DeadLetterMessage
accepte un objet azservicebus.Client
et un objet azservicebus.ReceivedMessage
. Il envoie ensuite le message à la file d’attente de lettres mortes. La fonction accepte deux paramètres : un contexte et un objet azservicebus.DeadLetterOptions
. La fonction Receiver.DeadLetterMessage
retourne une erreur si l’envoi du message vers la file d’attente de lettres mortes échoue.
Pour recevoir des messages de la file d’attente de lettres mortes, ajoutez la fonction ReceiveDeadLetterMessage
à votre fichier main.go
.
func GetDeadLetterMessage(client *azservicebus.Client) {
receiver, err := client.NewReceiverForQueue(
"myqueue",
&azservicebus.ReceiverOptions{
SubQueue: azservicebus.SubQueueDeadLetter,
},
)
if err != nil {
panic(err)
}
defer receiver.Close(context.TODO())
messages, err := receiver.ReceiveMessages(context.TODO(), 1, nil)
if err != nil {
panic(err)
}
for _, message := range messages {
fmt.Printf("DeadLetter Reason: %s\nDeadLetter Description: %s\n", *message.DeadLetterReason, *message.DeadLetterErrorDescription) //change to struct an unmarshal into it
err := receiver.CompleteMessage(context.TODO(), message, nil)
if err != nil {
panic(err)
}
}
}
GetDeadLetterMessage
accepte un objet azservicebus.Client
et crée un objet azservicebus.Receiver
avec des options pour la file d’attente de lettres mortes. Il reçoit ensuite les messages de la file d’attente de lettres mortes. La fonction reçoit ensuite un message de la file d’attente de lettres mortes. Ensuite, elle imprime le motif de lettre morte du message et sa description.
Exemple de code
package main
import (
"context"
"errors"
"fmt"
"os"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus"
)
func GetClient() *azservicebus.Client {
namespace, ok := os.LookupEnv("AZURE_SERVICEBUS_HOSTNAME") //ex: myservicebus.servicebus.windows.net
if !ok {
panic("AZURE_SERVICEBUS_HOSTNAME environment variable not found")
}
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
panic(err)
}
client, err := azservicebus.NewClient(namespace, cred, nil)
if err != nil {
panic(err)
}
return client
}
func SendMessage(message string, client *azservicebus.Client) {
sender, err := client.NewSender("myqueue", nil)
if err != nil {
panic(err)
}
defer sender.Close(context.TODO())
sbMessage := &azservicebus.Message{
Body: []byte(message),
}
err = sender.SendMessage(context.TODO(), sbMessage, nil)
if err != nil {
panic(err)
}
}
func SendMessageBatch(messages []string, client *azservicebus.Client) {
sender, err := client.NewSender("myqueue", nil)
if err != nil {
panic(err)
}
defer sender.Close(context.TODO())
batch, err := sender.NewMessageBatch(context.TODO(), nil)
if err != nil {
panic(err)
}
for _, message := range messages {
err := batch.AddMessage(&azservicebus.Message{Body: []byte(message)}, nil)
if errors.Is(err, azservicebus.ErrMessageTooLarge) {
fmt.Printf("Message batch is full. We should send it and create a new one.\n")
}
}
if err := sender.SendMessageBatch(context.TODO(), batch, nil); err != nil {
panic(err)
}
}
func GetMessage(count int, client *azservicebus.Client) {
receiver, err := client.NewReceiverForQueue("myqueue", nil)
if err != nil {
panic(err)
}
defer receiver.Close(context.TODO())
messages, err := receiver.ReceiveMessages(context.TODO(), count, nil)
if err != nil {
panic(err)
}
for _, message := range messages {
body := message.Body
fmt.Printf("%s\n", string(body))
err = receiver.CompleteMessage(context.TODO(), message, nil)
if err != nil {
panic(err)
}
}
}
func DeadLetterMessage(client *azservicebus.Client) {
deadLetterOptions := &azservicebus.DeadLetterOptions{
ErrorDescription: to.Ptr("exampleErrorDescription"),
Reason: to.Ptr("exampleReason"),
}
receiver, err := client.NewReceiverForQueue("myqueue", nil)
if err != nil {
panic(err)
}
defer receiver.Close(context.TODO())
messages, err := receiver.ReceiveMessages(context.TODO(), 1, nil)
if err != nil {
panic(err)
}
if len(messages) == 1 {
err := receiver.DeadLetterMessage(context.TODO(), messages[0], deadLetterOptions)
if err != nil {
panic(err)
}
}
}
func GetDeadLetterMessage(client *azservicebus.Client) {
receiver, err := client.NewReceiverForQueue(
"myqueue",
&azservicebus.ReceiverOptions{
SubQueue: azservicebus.SubQueueDeadLetter,
},
)
if err != nil {
panic(err)
}
defer receiver.Close(context.TODO())
messages, err := receiver.ReceiveMessages(context.TODO(), 1, nil)
if err != nil {
panic(err)
}
for _, message := range messages {
fmt.Printf("DeadLetter Reason: %s\nDeadLetter Description: %s\n", *message.DeadLetterReason, *message.DeadLetterErrorDescription)
err := receiver.CompleteMessage(context.TODO(), message, nil)
if err != nil {
panic(err)
}
}
}
func main() {
client := GetClient()
fmt.Println("send a single message...")
SendMessage("firstMessage", client)
fmt.Println("send two messages as a batch...")
messages := [2]string{"secondMessage", "thirdMessage"}
SendMessageBatch(messages[:], client)
fmt.Println("\nget all three messages:")
GetMessage(3, client)
fmt.Println("\nsend a message to the Dead Letter Queue:")
SendMessage("Send message to Dead Letter", client)
DeadLetterMessage(client)
GetDeadLetterMessage(client)
}
Exécuter le code
Avant d’exécuter le code, créez une variable d’environnement nommée AZURE_SERVICEBUS_HOSTNAME
. Définissez la valeur de la variable d’environnement sur l’espace de noms Service Bus.
export AZURE_SERVICEBUS_HOSTNAME=<YourServiceBusHostName>
Ensuite, exécutez la commande go run
suivante pour exécuter l’application :
go run main.go
Étapes suivantes
Pour plus d’informations, reportez-vous aux liens suivants :