Azure Service Bus: Mensajería confiable entre servicios
Resumen
Service Bus es el servicio de mensajería enterprise de Azure. Queues para comunicación punto a punto, Topics para pub/sub. setup completo con dead-letter queues y sessions.
¿Qué es Azure Service Bus?
Service Bus es un message broker managed para desacoplar aplicaciones. Garantiza entrega de mensajes con:
- At-least-once delivery: El mensaje llega mínimo 1 vez
- FIFO ordering: Con sessions
- Transactions: Operaciones atómicas
- Dead-letter queues: Manejo de mensajes problemáticos
Casos de uso: - Desacoplar microservicios - Order processing (ecommerce) - Event-driven architectures - Integration with on-premises systems
Crear namespace y queue
# Variables
RG="messaging-rg"
LOCATION="westeurope"
NAMESPACE="sb-prod-$(date +%s)"
QUEUE_NAME="orders"
# Crear resource group
az group create \
--name $RG \
--location $LOCATION
# Crear Service Bus namespace (Standard tier)
az servicebus namespace create \
--name $NAMESPACE \
--resource-group $RG \
--location $LOCATION \
--sku Standard
# Crear queue con dead-lettering
az servicebus queue create \
--name $QUEUE_NAME \
--namespace-name $NAMESPACE \
--resource-group $RG \
--enable-dead-lettering-on-message-expiration true \
--default-message-time-to-live PT1H \
--max-delivery-count 10
SKUs disponibles: - Basic: €0.05/million ops - Sin topics, sessions ni transactions - Standard: €10/mes + ops - Topics, sessions, auto-forward - Premium: €550/mes - Recursos dedicados, VNet integration
Queues vs Topics
Queues (punto a punto)
- Un solo consumer procesa cada mensaje
- FIFO si usas sessions
- Ideal para task queues
# Crear queue simple
az servicebus queue create \
--name tasks \
--namespace-name $NAMESPACE \
--resource-group $RG
Topics (pub/sub)
Sender → [Topic] → Subscription 1 → Receiver A
→ Subscription 2 → Receiver B
→ Subscription 3 → Receiver C
- Múltiples subscriptions
- Cada subscription recibe copia del mensaje
- Filters para routing
# Crear topic
az servicebus topic create \
--name events \
--namespace-name $NAMESPACE \
--resource-group $RG
# Crear subscriptions con filtros
az servicebus topic subscription create \
--name mobile-orders \
--namespace-name $NAMESPACE \
--topic-name events \
--resource-group $RG \
--enable-session true
az servicebus topic subscription create \
--name web-orders \
--namespace-name $NAMESPACE \
--topic-name events \
--resource-group $RG
Dead-Letter Queue (DLQ)
Mensajes van al DLQ cuando: - TTL expira (Time-to-Live) - MaxDeliveryCount excedido (defecto 10 reintentos) - Filtros no coinciden - Aplicación marca mensaje como dead-letter
# Habilitar DLQ en queue existente
az servicebus queue update \
--name $QUEUE_NAME \
--namespace-name $NAMESPACE \
--resource-group $RG \
--enable-dead-lettering-on-message-expiration true
# DLQ para subscription
az servicebus topic subscription update \
--name mobile-orders \
--namespace-name $NAMESPACE \
--topic-name events \
--resource-group $RG \
--enable-dead-lettering-on-message-expiration true
Procesar mensajes del DLQ
Path del DLQ:
Código C# para leer DLQ:
using Azure.Messaging.ServiceBus;
string connectionString = "<connection-string>";
string queueName = "orders";
await using var client = new ServiceBusClient(connectionString);
var receiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions
{
SubQueue = SubQueue.DeadLetter
});
var messages = await receiver.ReceiveMessagesAsync(maxMessages: 10);
foreach (var msg in messages)
{
Console.WriteLine($"DLQ Reason: {msg.DeadLetterReason}");
Console.WriteLine($"DLQ Description: {msg.DeadLetterErrorDescription}");
Console.WriteLine($"Body: {msg.Body}");
// Procesar y completar
await receiver.CompleteMessageAsync(msg);
}
Message Sessions (FIFO)
Sessions garantizan orden FIFO para mensajes relacionados:
# Crear queue con sessions
az servicebus queue create \
--name ordered-tasks \
--namespace-name $NAMESPACE \
--resource-group $RG \
--enable-session true
Código C# con sessions:
// Enviar mensajes con SessionId
var sender = client.CreateSender("ordered-tasks");
await sender.SendMessageAsync(new ServiceBusMessage("Order 1")
{
SessionId = "session-customer-123"
});
// Recibir por session
var sessionReceiver = await client.AcceptNextSessionAsync("ordered-tasks");
var messages = await sessionReceiver.ReceiveMessagesAsync(10);
Auto-forwarding
Encadena queues/topics automáticamente:
# Queue A → Queue B (auto-forward)
az servicebus queue create \
--name process-later \
--namespace-name $NAMESPACE \
--resource-group $RG \
--forward-to completed-tasks
# Topic subscription → Queue
az servicebus topic subscription create \
--name archive \
--namespace-name $NAMESPACE \
--topic-name events \
--resource-group $RG \
--forward-to archive-queue
Caso de uso: Filtrar mensajes del DLQ a otra queue para reprocesamiento.
Scheduled delivery
// Enviar mensaje para procesarse en 1 hora
var message = new ServiceBusMessage("Reminder");
message.ScheduledEnqueueTime = DateTimeOffset.UtcNow.AddHours(1);
await sender.SendMessageAsync(message);
Útil para: - Recordatorios - Retry con backoff exponencial - Batch processing diferido
Seguridad: Managed Identity
# Crear managed identity
az identity create \
--name app-identity \
--resource-group $RG
IDENTITY_ID=$(az identity show \
--name app-identity \
--resource-group $RG \
--query principalId -o tsv)
# Asignar rol Service Bus Data Sender
az role assignment create \
--role "Azure Service Bus Data Sender" \
--assignee $IDENTITY_ID \
--scope /subscriptions/{sub}/resourceGroups/$RG/providers/Microsoft.ServiceBus/namespaces/$NAMESPACE
# Asignar rol Service Bus Data Receiver
az role assignment create \
--role "Azure Service Bus Data Receiver" \
--assignee $IDENTITY_ID \
--scope /subscriptions/{sub}/resourceGroups/$RG/providers/Microsoft.ServiceBus/namespaces/$NAMESPACE
Código sin connection strings:
using Azure.Identity;
var credential = new DefaultAzureCredential();
var client = new ServiceBusClient(
"<namespace>.servicebus.windows.net",
credential
);
Monitoreo
# Ver count de mensajes en queue
az servicebus queue show \
--name $QUEUE_NAME \
--namespace-name $NAMESPACE \
--resource-group $RG \
--query "messageCount"
# Ver mensajes en DLQ
az servicebus queue show \
--name $QUEUE_NAME \
--namespace-name $NAMESPACE \
--resource-group $RG \
--query "deadLetterMessageCount"
# Metrics en Log Analytics
az monitor metrics list \
--resource /subscriptions/{sub}/resourceGroups/$RG/providers/Microsoft.ServiceBus/namespaces/$NAMESPACE \
--metric "ActiveMessages" \
--interval PT1H
Queries útiles:
// Mensajes en DLQ por queue
AzureMetrics
| where ResourceProvider == "MICROSOFT.SERVICEBUS"
| where MetricName == "DeadletteredMessages"
| summarize DeadLetterCount = max(Maximum) by Resource
| order by DeadLetterCount desc
// Latencia de procesamiento
ServiceBusLogs
| where OperationName == "CompleteMessage"
| extend Duration = DurationMs
| summarize AvgDuration = avg(Duration), P95 = percentile(Duration, 95)
Buenas prácticas
- MaxDeliveryCount: Ajusta según tu lógica de retry (defecto 10)
- TTL realista: No uses TTL infinito, causa acumulación
- Procesa DLQ: Monitorea y alertea en DLQ > 0
- Sessions solo si necesitas: Añade overhead
- Managed Identity: Nunca uses connection strings en código
- Prefetch: Habilita prefetch en receivers para throughput
- Batch: Envía mensajes en batch (hasta 100)
Quota exceeded
Si ves QuotaExceeded, revisa DLQ. Mensajes no procesados acumulan y bloquean nuevos envíos.
Troubleshooting común
# Error: Queue not found
# Solución: Verifica namespace correcto
az servicebus queue list \
--namespace-name $NAMESPACE \
--resource-group $RG
# Error: Max message size exceeded (256KB Standard, 1MB Premium)
# Solución: Reduce payload o usa Premium tier
# Mensajes no llegan
# 1. Verifica receiver activo
# 2. Revisa DLQ
# 3. Comprueba TTL no expiró