Using Azure Storage Queues with Go
This document guides you through interacting with Azure Storage Queues using the Azure SDK for Go.
Azure Queue Storage is a service that stores large numbers of messages that can be processed by a work queue. Each message in Queue Storage is up to 64 KB in size, and a queue can contain any number of messages, up to the limit of the storage account's capacity. Queue Storage is often used to decouple applications, enabling development, deployment, and scaling of different components independently.
Prerequisites
- An Azure Storage account. If you don't have one, you can create it using the Azure portal, Azure CLI, or Azure PowerShell.
- A Go development environment set up.
- The Azure SDK for Go installed. You can install the necessary packages with:
go get github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue - A connection string for your storage account or appropriate credentials.
Connecting to a Queue
To interact with a queue, you first need to create a client. You can use a connection string or a credential object.
Using a Connection String
package main
import (
"context"
"fmt"
"log"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue"
)
func main() {
// Replace with your actual connection string
connectionString := "DefaultEndpointsProtocol=https;AccountName=YOUR_ACCOUNT_NAME;AccountKey=YOUR_ACCOUNT_KEY;EndpointSuffix=core.windows.net"
// Replace with your queue name
queueName := "my-go-queue"
// Create a new client
client, err := azqueue.NewClientFromConnectionString(connectionString, nil)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
// Create the queue if it doesn't exist
_, err = client.CreateQueue(context.Background(), queueName, nil)
if err != nil {
// Ignore error if queue already exists
// A more robust check might be needed in production
// fmt.Printf("Warning: Failed to create queue, it might already exist: %v\n", err)
} else {
fmt.Printf("Queue '%s' created successfully.\n", queueName)
}
fmt.Printf("Successfully connected to queue: %s\n", queueName)
// You can now use the 'client' to perform queue operations
}
Sending a Message
To send a message to the queue, use the SendMessage method.
func sendMessage(ctx context.Context, client *azqueue.Client, queueName string, messageText string) {
_, err := client.SendMessage(ctx, queueName, messageText, nil)
if err != nil {
log.Fatalf("Failed to send message: %v", err)
}
fmt.Printf("Message sent: '%s'\n", messageText)
}
// In your main function:
// sendMessage(context.Background(), client, queueName, "Hello from Go!")
Receiving a Message
To receive messages, you can peek at them (without deleting) or dequeue them (which makes them invisible and deletes them after a visibility timeout).
Dequeuing a Message
Dequeuing a message retrieves it and makes it invisible to other consumers for a specified period. After processing, you must delete it.
func receiveAndDeleteMessage(ctx context.Context, client *azqueue.Client, queueName string) {
// Dequeue a message
resp, err := client.ReceiveMessage(ctx, queueName, nil)
if err != nil {
log.Fatalf("Failed to receive message: %v", err)
}
if len(resp.Messages) == 0 {
fmt.Println("No messages in the queue.")
return
}
message := resp.Messages[0] // Process the first message
fmt.Printf("Received message (ID: %s): %s\n", *message.ID, *message.MessageText)
// Delete the message after processing
_, err = client.DeleteMessage(ctx, queueName, *message.MessageID, *message.PopReceipt, nil)
if err != nil {
log.Fatalf("Failed to delete message: %v", err)
}
fmt.Printf("Message deleted.\n")
}
// In your main function:
// receiveAndDeleteMessage(context.Background(), client, queueName)
Peeking at Messages
Peeking allows you to see messages without making them invisible or deleting them.
func peekMessage(ctx context.Context, client *azqueue.Client, queueName string) {
resp, err := client.PeekMessages(ctx, queueName, nil)
if err != nil {
log.Fatalf("Failed to peek messages: %v", err)
}
if len(resp.Messages) == 0 {
fmt.Println("No messages to peek at.")
return
}
for _, message := range resp.Messages {
fmt.Printf("Peeked message: %s\n", *message.MessageText)
}
}
// In your main function:
// peekMessage(context.Background(), client, queueName)
Managing Queue Metadata
You can get and set approximate message counts and metadata for a queue.
Getting Queue Properties
func getQueueProperties(ctx context.Context, client *azqueue.Client, queueName string) {
resp, err := client.GetProperties(ctx, queueName, nil)
if err != nil {
log.Fatalf("Failed to get queue properties: %v", err)
}
fmt.Printf("Approximate message count for '%s': %d\n", queueName, *resp.ApproximateMessagesCount)
}
// In your main function:
// getQueueProperties(context.Background(), client, queueName)
Clearing a Queue
This operation removes all messages from the queue.
func clearQueue(ctx context.Context, client *azqueue.Client, queueName string) {
err := client.ClearMessages(ctx, queueName, nil)
if err != nil {
log.Fatalf("Failed to clear queue messages: %v", err)
}
fmt.Printf("All messages cleared from queue '%s'.\n", queueName)
}
// In your main function:
// clearQueue(context.Background(), client, queueName)
Deleting a Queue
func deleteQueue(ctx context.Context, client *azqueue.Client, queueName string) {
_, err := client.Delete(ctx, queueName, nil)
if err != nil {
log.Fatalf("Failed to delete queue: %v", err)
}
fmt.Printf("Queue '%s' deleted.\n", queueName)
}
// In your main function:
// deleteQueue(context.Background(), client, queueName)
Next Steps
Explore more advanced features such as:
- Setting visibility timeouts for messages.
- Implementing message batching for efficiency.
- Handling message processing errors and retries.
- Using Azure identity for authentication instead of connection strings.