Hoy, cuando un pasajero pulsa «Confirmar reserva» en app-contoso-reservas-pro, dentro de esa única petición HTTP pasan seis cosas seguidas: se cobra en la pasarela, se actualiza la disponibilidad, se encola la emisión de la tarjeta, se acreditan las millas, se avisa al sistema de facturación y se envía el correo de confirmación. Todo síncrono, todo en línea. La consecuencia es brutal y Contoso Airlines ya la ha sufrido: si el servicio de millas está lento, la compra falla. Un componente accesorio tumba el ingreso principal de la compañía.

Esta lección resuelve ese problema de raíz con desacoplamiento: los componentes dejan de llamarse unos a otros y pasan a intercambiar mensajes y eventos a través de una infraestructura intermedia. Verás los tres servicios que Azure ofrece para ello, cuándo usar cada uno, y las consecuencias de diseño que trae este modelo, que no son gratis.

Contenido

  1. Por qué desacoplar
  2. Mensaje frente a evento
  3. Los tres servicios comparados
  4. Azure Service Bus
  5. Azure Event Grid
  6. Azure Event Hubs
  7. El flujo completo de Contoso
  8. Entrega al menos una vez, ordenación e idempotencia
  9. Coste de cada servicio
  10. Errores Comunes y Consejos
  11. Ejercicios
  12. Conclusión

  1. Por qué desacoplar

Encadenar seis llamadas síncronas tiene tres defectos acumulativos. La disponibilidad se multiplica: si cada componente tiene un 99,9 %, la cadena de seis baja al 99,4 %, más de cuatro horas de caída al mes. La latencia se suma: el pasajero espera lo que tardan todos. Y el acoplamiento se congela: añadir un séptimo paso obliga a tocar y redesplegar el código de la compra.

Con un intermediario, la compra hace lo imprescindible —cobrar y reservar la plaza— y publica un hecho. Los demás reaccionan a su ritmo. Si el servicio de millas está caído, su mensaje espera en la cola y se procesa cuando vuelve; el pasajero ni se entera. Eso es el desacoplamiento: en el tiempo, en el espacio y en la disponibilidad.

  1. Mensaje frente a evento

Esta distinción es la que casi todo el mundo confunde, y de ella depende elegir bien el servicio.

Mensaje Evento
Qué expresa Una instrucción: haz esto Un hecho: esto ha ocurrido
Intención del emisor Espera que alguien lo procese No sabe ni le importa quién reacciona
Contenido La carga completa que hace falta Ligero: qué pasó, cuándo y sobre qué
Acoplamiento El emisor conoce al destinatario Ninguno
Si nadie lo consume Es un error: se queda en la cola Es normal: se descarta
Ejemplo en Contoso «Emite la tarjeta del localizador XR7742» «La reserva XR7742 se ha confirmado»

La regla mnemotécnica: un mensaje tiene destinatario e intención; un evento tiene emisor y pasado. La forma verbal lo delata —EmitirTarjeta frente a ReservaConfirmada— y no es cosmética: el mensaje va a Service Bus porque alguien tiene que procesarlo y no se puede perder; el evento va a Event Grid porque cero, uno o siete suscriptores pueden interesarse y el emisor sigue igual.

  1. Los tres servicios comparados

Service Bus Event Grid Event Hubs
Para qué Mensajería empresarial fiable Distribución de eventos discretos Ingesta masiva de telemetría
Unidad Mensaje (hasta 256 KB / 100 MB) Evento (64 KB) Registro (pequeño, en flujo)
Volumen típico Miles por segundo Millones por segundo Millones por segundo, sostenidos
Modelo de entrega El consumidor extrae El servicio empuja El consumidor lee por desplazamiento
Orden Sí, con sesiones No garantizado Sí, dentro de la partición
Reintentos y mensajes fallidos Completos Sí, con reintentos y cola El consumidor gestiona su posición
Retención Hasta que se consume 24 horas de reintentos Ventana de tiempo (1-7 días o más)
Caso en Contoso reservas-confirmadas ReservaConfirmada, blob nuevo Telemetría de mostradores

Y no olvides las colas de Azure Storage de 02-04: simples, muy baratas, sin temas ni sesiones ni transacciones, con mensajes de 64 KB y siete días de retención. Bastan cuando hay un solo consumidor, el orden da igual y no necesitas filtros ni entrega transaccional. cola-emision-tarjetas es exactamente ese caso y por eso sigue siendo una cola de Storage. En cuanto necesites temas, sesiones, detección de duplicados o transacciones, es Service Bus.

  1. Azure Service Bus

az servicebus namespace create -g rg-contoso-reservas-pro -n sb-contoso-pro \
  --location westeurope --sku Premium --capacity 1 \
  --tags entorno=produccion proyecto=contoso-reservas \
         centro-coste=CC-1042 [email protected]

# Un TEMA: un publicador, varios interesados con criterios distintos
az servicebus topic create -g rg-contoso-reservas-pro --namespace-name sb-contoso-pro \
  -n reservas-confirmadas --max-size 5120 --enable-duplicate-detection true

az servicebus topic subscription create -g rg-contoso-reservas-pro \
  --namespace-name sb-contoso-pro --topic-name reservas-confirmadas \
  -n tarjetas --max-delivery-count 5 --dead-lettering-on-message-expiration true

# Filtro: fidelizacion solo quiere las reservas de socios
az servicebus topic subscription rule create -g rg-contoso-reservas-pro \
  --namespace-name sb-contoso-pro --topic-name reservas-confirmadas \
  --subscription-name fidelizacion -n solo-socios \
  --filter-sql-expression "esSocio = true AND importe > 0"

Las piezas que hay que conocer:

  • Cola frente a tema. Una cola es punto a punto: cada mensaje lo procesa un consumidor. Un tema es publicación y suscripción: cada suscripción recibe su propia copia. Contoso usa un tema con las suscripciones tarjetas, facturacion y fidelizacion, de modo que añadir un cuarto interesado no toca el emisor.
  • Filtros de suscripción. Reglas SQL sobre las propiedades del mensaje. fidelizacion solo recibe reservas de socios, así que no ve lo que no le concierne: menos proceso y menos coste.
  • Sesiones. Sin ellas no hay orden garantizado. Con SessionId —por ejemplo, el localizador— todos los mensajes de esa sesión los procesa un solo consumidor y en orden. Es lo que permite garantizar que «reserva creada» se procese antes que «reserva modificada».
  • Bloqueo con vistazo. El modo de recepción correcto: el consumidor bloquea el mensaje sin borrarlo, trabaja, y solo entonces lo completa. Si el proceso muere, el bloqueo caduca y el mensaje vuelve a estar disponible. El modo alternativo, recibir y borrar, pierde mensajes ante cualquier fallo.
  • Aplazamiento. Apartar un mensaje que no se puede procesar todavía —falta un dato que llegará después— sin bloquear la cola, para recuperarlo luego por su número de secuencia.
  • Cola de mensajes con problemas de entrega. La pieza que salva a los equipos. Tras max-delivery-count intentos fallidos, el mensaje se mueve a una subcola en lugar de bloquear el proceso para siempre. Ahí se inspecciona, se corrige y se reenvía. Sin ella, un mensaje envenenado atasca la cola indefinidamente.
  • Transacciones y detección de duplicados. Se pueden agrupar varias operaciones —completar un mensaje y publicar otro— en una unidad atómica dentro del mismo espacio de nombres. Y con la detección de duplicados activada, el servicio descarta durante una ventana de tiempo los mensajes con el mismo MessageId.
Nivel Cuándo
Básico Solo colas. Ni temas ni sesiones: casi nunca sirve
Estándar Temas, sesiones, transacciones. Capacidad compartida y variable
Premium Recursos dedicados, rendimiento predecible, puntos privados. Producción

Emisión y consumo, con identidad administrada y sin cadenas de conexión:

// Publicar: el hecho lleva propiedades para que los filtros puedan actuar
var cliente = new ServiceBusClient("sb-contoso-pro.servicebus.windows.net",
                                   new DefaultAzureCredential());
var emisor = cliente.CreateSender("reservas-confirmadas");

var mensaje = new ServiceBusMessage(BinaryData.FromObjectAsJson(reserva))
{
    MessageId = reserva.Localizador,        // detección de duplicados
    SessionId = reserva.Localizador,        // orden por reserva
    ContentType = "application/json"
};
mensaje.ApplicationProperties["esSocio"] = reserva.EsSocio;   // usado por el filtro
mensaje.ApplicationProperties["importe"] = reserva.Importe;
await emisor.SendMessageAsync(mensaje);

// Consumir con bloqueo con vistazo: se completa SOLO si el trabajo terminó bien
var procesador = cliente.CreateProcessor("reservas-confirmadas", "tarjetas",
    new ServiceBusProcessorOptions { MaxConcurrentCalls = 10, AutoCompleteMessages = false });

procesador.ProcessMessageAsync += async args =>
{
    var reserva = args.Message.Body.ToObjectFromJson<Reserva>();
    try
    {
        await _emisorTarjetas.EmitirAsync(reserva);   // idempotente (06-03)
        await args.CompleteMessageAsync(args.Message);
    }
    catch (DatoInvalidoException ex)
    {
        // Error permanente: no tiene sentido reintentar, va directo a la subcola
        await args.DeadLetterMessageAsync(args.Message, "DatoInvalido", ex.Message);
    }
    // Cualquier otra excepción: no se completa, el bloqueo caduca y se reintenta
};
await procesador.StartProcessingAsync();

Fíjate en la distinción del catch: ante un error permanente se envía a la subcola de inmediato, porque reintentar cinco veces un dato malformado solo gasta tiempo; ante un error transitorio se deja que el bloqueo caduque y el mensaje se reintente solo.

  1. Azure Event Grid

Event Grid es un enrutador de eventos con publicación y suscripción por envío: el servicio empuja el evento al destino y gestiona los reintentos. No hay que sondear nada.

  • Temas del sistema: los propios servicios de Azure publican eventos sin configuración. Un blob nuevo en sttarjetascontosopro emite Microsoft.Storage.BlobCreated, y Contoso lo usa para disparar la indexación de la tarjeta recién generada. Lo mismo con Key Vault avisando de un certificado a punto de caducar, o con ACR avisando de una imagen nueva.
  • Temas personalizados: los publicas tú, y ahí va ReservaConfirmada.
  • Esquema CloudEvents: el estándar de la CNCF, y el recomendado hoy frente al esquema propio de Event Grid, porque hace los eventos portables.
  • Filtros: por tipo de evento, por prefijo o sufijo del sujeto y por valores de propiedades avanzadas. El filtrado ocurre en el servicio, así que el suscriptor solo recibe lo que le interesa.
  • Reintentos y cola de eventos fallidos: si el destino no responde, reintenta con espera exponencial durante 24 horas y luego deposita el evento en una cuenta de almacenamiento configurada. Si no la configuras, el evento se pierde en silencio, que es la trampa más común del servicio.
az eventgrid topic create -g rg-contoso-reservas-pro -n evgt-contoso-reservas-pro \
  --location westeurope --input-schema cloudeventschemav1_0

az eventgrid event-subscription create --name sub-motor-disponibilidad \
  --source-resource-id $(az eventgrid topic show -g rg-contoso-reservas-pro \
      -n evgt-contoso-reservas-pro --query id -o tsv) \
  --endpoint-type azurefunction \
  --endpoint "<id de la funcion>" \
  --included-event-types Contoso.Reservas.ReservaConfirmada \
  --advanced-filter data.importe NumberGreaterThan 500 \
  --deadletter-endpoint "<id del contenedor de eventos fallidos>"

El evento en CloudEvents, mostrando lo esencial: es ligero y describe un hecho, no lleva la reserva entera.

{
  "specversion": "1.0",
  "type": "Contoso.Reservas.ReservaConfirmada",
  "source": "/contoso/reservas/app-contoso-reservas-pro",
  "id": "b41f7c22-9e0a-4a11-9a3c-7d2f5c1e8a90",
  "subject": "reservas/XR7742",
  "time": "2026-08-15T09:14:22Z",
  "datacontenttype": "application/json",
  "data": { "localizador": "XR7742", "vuelo": "CA-1187",
            "origenDestino": "BCN-CDG", "importe": 214.50, "esSocio": true }
}

type permite filtrar por clase de evento, subject por recurso concreto —con filtros de prefijo como reservas/XR—, e id es el identificador que el consumidor usa para detectar duplicados.

  1. Azure Event Hubs

Event Hubs no es para eventos de negocio sino para flujos de datos a gran escala: telemetría, registros, series temporales. Contoso lo usa para los mostradores de facturación, que emiten sin parar el estado de la cola de pasajeros, el tiempo de atención y las incidencias de equipaje.

  • Particiones: el flujo se divide en particiones que se leen en paralelo. El orden se garantiza dentro de una partición, así que la clave de partición —el identificador del mostrador— determina qué queda ordenado. El número de particiones fija el paralelismo máximo y conviene pensarlo al crear el recurso.
  • Grupos de consumidores: cada aplicación consumidora tiene su propia vista del flujo con su propio avance. El panel en tiempo real y el proceso analítico leen los mismos datos sin estorbarse.
  • Retención: los registros no se borran al leerse; permanecen una ventana de tiempo, de 1 a 7 días en Estándar y más en Premium. Eso permite reprocesar volviendo atrás en el desplazamiento, algo imposible con una cola.
  • Captura: escribe automáticamente el flujo en Avro sobre stlagocontosopro, en la capa bronce del Data Lake (03-06), sin escribir una línea de código. Esta es la integración clave con la analítica.
  • Compatibilidad con Kafka: un productor o consumidor de Kafka apunta a Event Hubs cambiando la configuración de conexión, sin tocar el código. Es la vía de migración sin operar un clúster.
az eventhubs namespace create -g rg-contoso-reservas-pro -n evhns-contoso-telemetria-pro \
  --location westeurope --sku Standard --capacity 2 --enable-auto-inflate --maximum-throughput-units 10

az eventhubs eventhub create -g rg-contoso-reservas-pro \
  --namespace-name evhns-contoso-telemetria-pro -n facturacion-mostradores \
  --partition-count 8 --retention-time-in-hours 72 \
  --enable-capture true --capture-interval 300 \
  --destination-name EventHubArchive.AzureBlockBlob \
  --storage-account stlagocontosopro --blob-container bronce

--enable-auto-inflate sube las unidades de rendimiento automáticamente ante un pico —y aquí va el aviso de coste: sube solas, pero no bajan solas, así que un pico puntual deja el recurso facturando al máximo hasta que alguien lo ajusta—.

  1. El flujo completo de Contoso

graph LR
  WEB["app-contoso-reservas-pro<br/>Confirmar reserva"] -->|1 mensaje| SB["Service Bus<br/>tema reservas-confirmadas"]
  WEB -->|2 evento| EG["Event Grid<br/>evgt-contoso-reservas-pro"]
  SB --> S1["Suscripcion tarjetas"] --> F1["Function<br/>GenerarTarjetaEmbarque"]
  SB --> S2["Suscripcion facturacion"] --> CA["ca-motor-facturacion"]
  SB --> S3["Suscripcion fidelizacion<br/>filtro esSocio = true"] --> F2["Function<br/>AcreditarMillas"]
  F1 --> BLOB["sttarjetascontosopro<br/>tarjetas-embarque"]
  BLOB -->|BlobCreated| EG2["Event Grid<br/>tema del sistema"] --> LA["Logic App:<br/>notificar al pasajero"]
  EG --> ML["Modelo de demanda"]
  MOS["Mostradores de facturacion"] -->|telemetria| EH["Event Hubs<br/>facturacion-mostradores"]
  EH -->|captura| LAGO["stlagocontosopro / bronce"]
  EH --> PANEL["Panel de operaciones<br/>en tiempo real"]
  SB -.->|fallos| DLQ["Cola de mensajes<br/>con problemas de entrega"]

Léelo como una decisión de diseño en cada flecha. La confirmación publica un mensaje en el tema, porque emitir la tarjeta, facturar y acreditar millas tienen que ocurrir y no pueden perderse; y publica un evento en Event Grid, porque puede haber interesados que hoy no existen —el modelo de predicción de demanda es uno— sin que el emisor los conozca. Cuando la función deja el PDF en el contenedor, el tema del sistema de Storage emite BlobCreated y una aplicación lógica (06-04) notifica al pasajero: nadie tuvo que programar esa conexión. La telemetría de los mostradores va por Event Hubs, con captura automática hacia el Data Lake y lectura simultánea del panel en tiempo real desde otro grupo de consumidores. Y la petición del pasajero termina en cuanto se cobra y se reserva la plaza: si fidelización está caído, su mensaje espera en la suscripción y la compra no se entera. Ese era el problema del principio, y está resuelto.

  1. Entrega al menos una vez, ordenación e idempotencia

Estas son las tres consecuencias inevitables del modelo, y conviene aceptarlas como parte del diseño y no como sorpresas.

Entrega al menos una vez. Los tres servicios garantizan que el mensaje llega, no que llega una sola vez. Un consumidor puede recibir un duplicado si se cae tras procesar y antes de completar, si el bloqueo caduca por tardar demasiado, o si el emisor reintenta al no recibir la confirmación. La entrega exactamente una vez de extremo a extremo no existe en un sistema distribuido; lo que existe es procesamiento idempotente, que la vuelve innecesaria.

Ordenación. Por defecto no hay orden global. Se consigue orden por sesión en Service Bus y por partición en Event Hubs, y Event Grid no lo garantiza de ninguna forma. Diseña para que el orden no importe siempre que puedas —incluyendo una marca de tiempo o un número de versión en la carga y descartando lo viejo—, y reserva las sesiones para los casos en que de verdad haga falta, porque limitan el paralelismo.

Idempotencia, ya vista en 06-03 y ahora obligatoria en todo consumidor. Las tres herramientas: MessageId con detección de duplicados en Service Bus, que resuelve la ventana corta; el identificador de evento registrado por el consumidor, con la tabla registroembarques de stoperacionescontosopro; y las operaciones naturalmente idempotentes, escribir con clave determinista o upsert en lugar de insert. Esta última es siempre la mejor porque no necesita infraestructura adicional.

  1. Coste de cada servicio

Servicio Cómo se factura Qué dispara la factura
Colas de Storage Por transacción y almacenamiento Casi nada; es la opción más barata
Service Bus Estándar Por operación, con base mensual El sondeo agresivo: cada intento de recepción vacío es una operación
Service Bus Premium Por unidad de mensajería y hora Dimensionar de más «por si acaso»
Event Grid Por operación (millón de operaciones) Suscripciones sin filtrar que reciben todo
Event Hubs Por unidad de rendimiento y hora + eventos El escalado automático que sube y no baja, y la captura

Tres consejos concretos: usa recepción con espera larga en Service Bus en lugar de sondear en bucle, porque una recepción vacía cada segundo son 2,6 millones de operaciones al mes por consumidor; filtra en el servicio, no en el consumidor, porque lo que se filtra en Event Grid no se factura como entrega; y revisa las unidades de rendimiento de Event Hubs después de cada pico, porque auto-inflate sube pero no baja. En desarrollo, elimina los espacios de nombres que no se usen: un Service Bus Premium o un Event Hubs con unidades reservadas facturan estén vacíos o llenos.

Errores Comunes y Consejos

  • Usar Event Hubs para mensajería de negocio. No tiene bloqueo por mensaje ni cola de mensajes fallidos: la gestión de fallos es tuya y acabarás reimplementando Service Bus mal.
  • No configurar la cola de mensajes fallidos en Service Bus ni el destino de eventos fallidos en Event Grid. Los fallos se vuelven invisibles y los datos se pierden.
  • Meter la carga completa en el evento. Un evento describe un hecho y lleva una referencia; si necesitas mandar 5 MB, súbelo a sttarjetascontosopro y manda su URI.
  • Asumir orden donde no lo hay. Si el orden es imprescindible, sesiones o particiones; si no, marca de versión en la carga.
  • No hacer idempotente el consumidor. Duplicados esporádicos, irreproducibles y siempre en producción.
  • Reintentar indefinidamente un error permanente. Distingue lo transitorio de lo permanente y manda lo segundo a la subcola de inmediato.
  • Sondear en bucle cerrado. Dispara la factura de operaciones. Recepción con espera larga.
  • Consejo: pon nombre de hecho en pasado a los eventos (ReservaConfirmada) y de instrucción a los mensajes (EmitirTarjeta). El nombre obliga a decidir cuál es cuál, y con eso el servicio se elige solo.
  • Consejo: versiona el esquema desde el primer evento, con Contoso.Reservas.ReservaConfirmada.v1. El día que cambie la carga, los consumidores antiguos seguirán funcionando.

Ejercicios

Ejercicio 1. Contoso Millas quiere que, al completarse un vuelo, se acrediten las millas al socio, se recalcule su nivel y se envíe un resumen mensual; además, el equipo de datos quiere todos los eventos de vuelo completado para su modelo de predicción, y los tornos de embarque emiten 400 lecturas por segundo que hay que archivar y visualizar en directo.

  1. Asigna cada necesidad a un servicio y justifica la elección con la distinción mensaje/evento.
  2. Diseña el tema, las suscripciones y sus filtros para la parte de Service Bus.
  3. Indica las etiquetas obligatorias y una medida de ahorro para el entorno de desarrollo.

Ejercicio 2. La suscripción facturacion acumula 12.000 mensajes en su cola de mensajes con problemas de entrega. Al inspeccionarlos, todos son del mismo día y tienen DeadLetterReason: MaxDeliveryCountExceeded.

  1. ¿Qué ocurrió y por qué la cola principal siguió funcionando?
  2. Describe el procedimiento para recuperarlos, indicando qué hay que verificar antes de reenviar.
  3. Propón dos medidas para que no vuelva a pasar y una alerta.

Ejercicio 3. Un consumidor de reservas-confirmadas tarda unos 8 minutos en procesar cada mensaje porque llama a un sistema externo lento. El bloqueo de Service Bus es de 5 minutos. Explica qué está pasando, qué se ve en producción y da dos soluciones de naturaleza distinta.

Soluciones

Solución 1:

  1. Acreditar millas y recalcular el nivel son mensajes: son instrucciones que tienen que ejecutarse y no pueden perderse, así que Service Bus. El aviso al equipo de datos es un evento —«vuelo completado», un hecho al que se suscribe quien quiera, y mañana quizá otros— así que Event Grid. Las 400 lecturas por segundo de los tornos son telemetría de alto volumen que hay que archivar y ver en directo: Event Hubs con captura al Data Lake y un segundo grupo de consumidores para el panel.
  2. Tema vuelos-completados en sb-contoso-pro, con la suscripción millas sin filtro y la suscripción nivel-fidelidad con el filtro esSocio = true AND millasAcreditadas > 0. Ambas con max-delivery-count 5 y envío a la subcola activado. El resumen mensual no es una suscripción: es un proceso programado, y meterlo aquí sería confundir mensajería con planificación.
  3. entorno, proyecto=contoso-millas, centro-coste=CC-2077 y propietario. Ahorro en desarrollo: nivel Estándar en lugar de Premium para Service Bus, una sola unidad de rendimiento sin auto-inflate en Event Hubs con retención de 24 horas, y eliminar los espacios de nombres cuando no se usen, porque facturan aunque estén vacíos.

Solución 2:

  1. El consumidor de facturación falló de forma sistemática durante ese día —un despliegue con un error, o el sistema de facturación caído—. Cada mensaje se reintentó 5 veces y, al superar max-delivery-count, Service Bus lo movió automáticamente a la subcola. Justo por eso la cola principal siguió funcionando: sin ese mecanismo, el primer mensaje envenenado habría bloqueado el proceso y el resto de suscripciones también se habrían visto afectadas. La subcola hizo exactamente su trabajo.
  2. Antes de reenviar nada, hay que verificar tres cosas: que la causa raíz está corregida y desplegada, que el consumidor es idempotente —porque parte de esos mensajes pueden haberse procesado parcialmente— y qué dice DeadLetterReason y DeadLetterErrorDescription de una muestra representativa, por si hay más de una causa mezclada. Después se leen los mensajes de la subcola y se reenvían al tema en lotes controlados, vigilando la cola principal para no repetir el atasco.
  3. Medidas: (a) distinguir en el código los errores permanentes de los transitorios y mandar los primeros a la subcola de inmediato, sin agotar cinco intentos; (b) un interruptor que pause el consumidor cuando la tasa de fallos supera un umbral, para que los mensajes esperen en la cola en lugar de quemar sus reintentos contra un sistema caído. La alerta: sobre la longitud de la subcola, con umbral bajo —diez mensajes— y aviso al equipo de guardia, porque 12.000 mensajes significan que nadie miraba.

Solución 3: El bloqueo caduca a los 5 minutos mientras el consumidor sigue trabajando; Service Bus da el mensaje por no procesado y lo entrega a otro consumidor. Cuando el primero termina y llama a CompleteMessageAsync, falla con un error de bloqueo perdido. En producción se ve como mensajes procesados dos y tres veces, un contador de entregas que crece hasta agotarse y mensajes que acaban en la subcola pese a haberse procesado correctamente. Solución (a), táctica: renovar el bloqueo automáticamente mientras se trabaja (MaxAutoLockRenewalDuration) y ampliar la duración del bloqueo de la suscripción. Solución (b), de diseño y mejor: sacar la llamada lenta del consumidor; completar el mensaje enseguida y delegar la parte lenta en un flujo aparte —una orquestación de Durable Functions o una segunda cola—, porque tener un mensaje bloqueado ocho minutos limita el rendimiento del sistema entero.

Conclusión

Has resuelto el problema con el que empezaba la lección. Sabes por qué desacoplar: la disponibilidad se multiplica a la baja, la latencia se suma y el acoplamiento congela la evolución; con un intermediario, la compra hace lo imprescindible y publica, y un componente accesorio caído deja de tumbar el ingreso principal. Tienes clara la distinción que casi todo el mundo confunde: un mensaje es una instrucción con destinatario que no se puede perder; un evento es un hecho en pasado que el emisor publica sin saber quién reacciona. Y sabes que el nombre lo delata.

Manejas los tres servicios con criterio. Service Bus para mensajería empresarial fiable: colas frente a temas con suscripciones y filtros SQL, sesiones para ordenar, bloqueo con vistazo como modo de recepción correcto, aplazamiento, cola de mensajes con problemas de entrega —la pieza que salva a los equipos—, transacciones, detección de duplicados y sus tres niveles, con el código de emisión y consumo de reservas-confirmadas distinguiendo el error permanente del transitorio. Event Grid para distribuir eventos discretos: temas del sistema que emiten sin configurar nada —el BlobCreated de sttarjetascontosopro—, temas personalizados, esquema CloudEvents, filtrado en el servicio y el destino de eventos fallidos que hay que configurar o los eventos se pierden en silencio. Y Event Hubs para ingesta masiva: particiones y orden dentro de la partición, grupos de consumidores independientes, retención que permite reprocesar, captura automática hacia la capa bronce de stlagocontosopro y compatibilidad con Kafka. Sin olvidar que las humildes colas de Storage bastan cuando hay un solo consumidor y ninguna exigencia.

Has diseñado el flujo completo de Contoso viendo cada decisión, y te llevas las tres consecuencias inevitables: entrega al menos una vez —la entrega exactamente una vez no existe, lo que existe es procesamiento idempotente—, ordenación solo por sesión o por partición, e idempotencia obligatoria en todo consumidor. Más el coste de cada servicio y lo que lo dispara: el sondeo en bucle, las suscripciones sin filtrar y el escalado automático que sube y no baja.

Con esto, la plataforma de Contoso está modernizada: contenedores, orquestación, funciones, integraciones y una arquitectura de eventos que la sostiene. Queda dar el último paso del módulo, y es de otra naturaleza. Contoso tiene ahora datos que antes no podía aprovechar —miles de reclamaciones de pasajeros escritas en texto libre, pasaportes que un agente teclea a mano en el check-in, avisos de embarque que solo se dan en dos idiomas, un portal que no se entiende fuera de España— y para todo eso existen servicios listos. La lección siguiente, Servicios de IA de Azure, recorre ese catálogo, implementa los casos concretos de Contoso, explica Azure OpenAI Service y la generación aumentada por recuperación para el asistente de atención al pasajero, y dedica el espacio que merece a lo que no es opcional: sesgos, alucinaciones, privacidad de los datos que se envían al servicio y la revisión previa por los equipos legal y de compliance.

Curso de Azure

Módulo 1: Introducción a Azure

Módulo 2: Servicios principales de Azure

Módulo 3: Bases de datos de Azure

Módulo 4: Seguridad en Azure

Módulo 5: Azure DevOps

Módulo 6: Servicios avanzados de Azure

Módulo 7: Monitoreo y gestión

Módulo 8: Gestión y optimización de costos

Módulo 9: Estudios de caso y mejores prácticas

© Copyright 2026. Todos los derechos reservados