Exportar (0) Imprimir
Expandir todo

Crear aplicaciones que usan colas de Service Bus

Actualizado: octubre de 2014

Este artículo describe la utilidad de las colas y muestra cómo escribir una aplicación simple basada en colas que utiliza Microsoft Azure Service Bus.

Supongamos un escenario en el sector de la venta directa en que los datos de venta de los terminales individuales de Puntos de venta (TPV) deben dirigirse a un sistema de administración del inventario que utiliza esos datos para determinar cuándo deben reponerse las existencias. La solución siguiente utiliza mensajería CmdLets para la comunicación entre los terminales y el sistema de administración del inventario, como se ilustra a continuación:

Colas-del-bus-de-servicio-imagen1

Cada terminal de punto de venta informa de sus datos de venta enviando mensajes a DataCollectionQueue. Estos mensajes permanecen en la cola hasta que el sistema de administración del inventario los recupera. A menudo, este patrón se denomina mensajería asincrónica, ya que el terminal de punto de venta no tiene que esperar una respuesta del sistema de administración de inventario para continuar procesando.

Antes de que miremos el código necesario para configurar esta aplicación, tenga en cuenta las ventajas de utilizar una cola en este escenario en lugar de hacer que los terminales de punto de venta se comuniquen directamente (de forma sincrónica) con el sistema de administración del inventario.

Con el patrón de mensajería asincrónica, los productores y consumidores no tienen que estar en línea al mismo tiempo. La infraestructura de mensajería almacena de forma confiable los mensajes hasta que la parte consumidora esté preparada para recibirlos. Esto permite a los componentes de la aplicación distribuida estar desconectados, ya sea voluntariamente (por ejemplo, para realizar tareas de mantenimiento) o debido al bloqueo de un componente, sin que ello afecte al sistema completo. Además, la aplicación que consume puede que tenga que estar en línea solo durante ciertos momentos del día. Por ejemplo, en este escenario de venta directa, el sistema de administración de inventario puede que solo tenga que estar en línea tras el final del día laborable.

En muchas aplicaciones, la carga del sistema cambia con el tiempo, mientras que el tiempo de procesamiento necesario para cada unidad de trabajo es constante de forma habitual. Intermediar entre los consumidores y productores de mensajes con una cola significa que la aplicación que consume (el trabajador) solo tiene que aprovisionarse para servir una carga media en lugar de una carga máxima. La profundidad de la cola aumentará y disminuirá según la carga entrante. Esto directamente ahorra dinero en cuanto a la cantidad de infraestructura necesaria para servir la carga de aplicación.

Colas-del-bus-de-servicio-imagen2

Conforme la carga aumenta, se pueden agregar más procesos de trabajo para leer desde la cola de trabajo. Cada mensaje es procesado solo por uno de los procesos de trabajo. Además, este equilibrio de carga basado en la extracción permite un uso óptimo de los equipos de trabajo incluso si estos difieren en cuanto a la capacidad de procesamiento, ya que extraerán mensajes a su propia velocidad máxima. Este patrón a menudo se denomina consumidor en competencia.

Colas-del-bus-de-servicio-imagen3

Al utilizar las colas de mensajes para intermediar entre productores y consumidores de mensajes se proporciona un acoplamiento débil intrínseco entre los componentes. Como los productores y los consumidores no están al tanto unos de otros, un consumidor se puede actualizar sin que tenga ningún efecto en el productor. Además, la topología de mensajes puede evolucionar sin que afecte a los extremos existentes. Hablaremos más de esto cuando tratemos la publicación/suscripción.

La sección siguiente indica cómo usar CmdLets para crear esta aplicación.

Necesitará una cuenta en el para poder empezar a trabajar con CmdLets. Si aún no tiene una, puede solicitar una prueba gratuita aquí. Se le pide que inicie sesión con un Windows Live ID (cuenta de Microsoft), que se asociará con su cuenta de CmdLets. Cuando lo haya hecho, podrá crear una nueva suscripción de CmdLets. En el futuro, cuando inicie sesión con su Windows Live ID (cuenta de Microsoft), tendrá acceso a todas las suscripciones de CmdLets asociadas con su cuenta.

Cuando tenga una suscripción, podrá crear un nuevo espacio de nombres de servicio. Deberá dar a su nuevo espacio de nombres de servicio un nombre exclusivo en todas las cuentas de CmdLets. Cada espacio de nombres de servicio actúa como contenedor de un conjunto de entidades de CmdLets. Para obtener más información, vea Procedimiento: Crear o modificar un espacio de nombres de servicio de Service Bus.

Para utilizar el CmdLets espacio de nombres de servicio, una aplicación debe hacer referencia al ensamblado de CmdLets, específicamente Microsoft.ServiceBus.dll. Puede encontrar este ensamblado como parte del Microsoft Azure SDK y la descarga está disponible en la página de descargas de Azure SDK. No obstante, el paquete NuGet de CmdLets es la forma más fácil de obtener la API de CmdLets y configurar la aplicación con todas las dependencias de CmdLets. Para obtener detalles sobre el uso de NuGet y el paquete de CmdLets, vea Usar el paquete NuGet de Bus de servicio.

Las operaciones de administración para entidades de mensajería de CmdLets (colas y temas de publicación/suscripción) se realizan a través de la clase NamespaceManager. CmdLets utiliza un modelo de seguridad basado en notificaciones implementado utilizando el Active Directory Access Control de Microsoft Azure (también conocido como Access Control Service o ACS). Son necesarias las credenciales adecuadas para crear una instancia de NamespaceManager para un espacio de nombres de servicio determinado. La clase TokenProvider representa un proveedor de tokens de seguridad con métodos de fábrica integrados que devuelven algunos proveedores de tokens bien conocidos. Utilizaremos una clase SharedSecretTokenProvider para almacenar las credenciales secretas compartidas y manejar la adquisición de los tokens adecuados de ACS. La instancia de NamespaceManager se crea entonces con la dirección base del CmdLets espacio de nombres de servicio y el proveedor de tokens.

La clase NamespaceManager proporciona métodos para crear, enumerar y eliminar entidades de mensajería. El fragmento que se muestra aquí indica cómo se crea y se utiliza la instancia de NamespaceManager para crear la cola de DataCollectionQueue.

Uri uri = ServiceBusEnvironment.CreateServiceUri("sb""ingham-blog"string.Empty);
string name = "owner";
string key = "abcdefghijklmopqrstuvwxyz";
 
TokenProvider tokenProvider = 
    TokenProvider.CreateSharedSecretTokenProvider(name, key);
NamespaceManager namespaceManager = 
    new NamespaceManager(uri, tokenProvider);
namespaceManager.CreateQueue("DataCollectionQueue");

Recuerde que hay sobrecargas del método CreateQueue que permiten que se ajusten las propiedades de la cola. Por ejemplo, puede establecer el valor de período de vida (TTL) predeterminado para mensajes enviados a la cola.

Para operaciones de tiempo de ejecución en entidades de CmdLets; por ejemplo, enviar y recibir mensajes, una aplicación tiene que crear primero un objeto de MessagingFactory. De forma parecida a la clase NamespaceManager, la instancia de MessagingFactory se crea a partir de la dirección base del espacio de nombres de servicio y el proveedor de tokens.

 MessagingFactory factory = MessagingFactory.Create(uri, tokenProvider);

Los mensajes enviados a y recibidos de las colas de CmdLets son instancias de la clase BrokeredMessage. Esta clase consta de un conjunto de propiedades estándar (como Label y TimeToLive), un diccionario que se utiliza para almacenar propiedades de la aplicación y un cuerpo de datos de aplicación arbitrarios. Una aplicación puede establecer el cuerpo pasando cualquier objeto serializable (el siguiente ejemplo pasa un objeto SalesData que representa los datos de venta del terminal de punto de venta), que utilizará el DataContractSerializer para serializar el objeto. De forma alternativa, se puede proporcionar un Stream.

 BrokeredMessage bm = new BrokeredMessage(salesData);
 bm.Label = "SalesReport";
 bm.Properties["StoreName"] = "Redmond";
 bm.Properties["MachineID"] = "POS_1";

La manera más sencilla de enviar mensajes a una cola determinada, en nuestro caso la DataCollectionQueue, es usar CreateMessageSender para crear un objeto MessageSender directamente desde la instancia MessagingFactory.

MessageSender sender = factory.CreateMessageSender("DataCollectionQueue");
sender.Send(bm);

La forma más sencilla de recibir mensajes desde la cola es usar un objeto MessageReceiver que puede crear directamente desde el MessagingFactory mediante CreateMessageReceiver. Los receptores de mensajes pueden trabajar en dos modos distintos: ReceiveAndDelete y PeekLock. El ReceiveMode se establece cuando se crea el receptor del mensaje, como un parámetro para la llamada de CreateMessageReceiver.

Al utilizar el modo ReceiveAndDelete, la recepción es una operación de una sola fase; es decir, cuando el CmdLets recibe la solicitud, marca el mensaje como consumido y lo devuelve a la aplicación. El modo ReceiveAndDelete es el modelo más sencillo y funciona mejor para escenarios en los que la aplicación puede tolerar no procesar un mensaje si fuera a ocurrir un error. Para comprender esto, piense en un escenario en el que el consumidor emite la solicitud de recepción y luego se bloquea antes de procesarla. Ya que CmdLets marcó el mensaje como consumido, cuando la aplicación se reinicie y empiece a consumir mensajes de nuevo, habrá perdido el mensaje que se consumió antes del bloqueo.

En el modo PeekLock, la recepción se convierte en una operación de dos fases que hace posible admitir aplicaciones que no pueden tolerar mensajes perdidos. Cuando el CmdLets recibe la solicitud, encuentra el siguiente mensaje que se va a consumir, lo bloquea para evitar que lo reciban otros consumidores y lo devuelve a la aplicación. Una vez que la aplicación termina de procesar el mensaje (o lo almacena de manera fiable para el procesamiento futuro), completa la segunda fase del proceso de recepción llamando a Complete en el mensaje recibido. Cuando el CmdLets vea el Complete, marcará el mensaje como consumido.

Hay dos resultados posibles. Primero, si la aplicación no puede procesar el mensaje por alguna razón, puede llamar a Abandon en el mensaje recibido (en lugar de Complete). Esto hará que CmdLets desbloquee el mensaje y hará que esté disponible para recibirse de nuevo, ya sea por el mismo consumidor o por otro consumidor que esté completando. Segundo, hay un tiempo de espera asociado con el bloqueo y, si la aplicación no puede procesar el mensaje antes de que caduque el tiempo de espera de bloqueo (por ejemplo, si la aplicación se bloquea), entonces el CmdLets desbloqueará el mensaje y hará que esté disponible para recibirse de nuevo.

Algo que hay que recordar es que si la aplicación se bloquea tras procesar el mensaje pero antes de que la solicitud de Complete se emita, el mensaje se volverá a enviar a la aplicación cuando se reinicie. Esto se suele denominar procesamiento Una vez como mínimo. Esto significa que cada mensaje se procesará al menos una vez pero en determinadas situaciones se puede volver a enviar el mismo mensaje. Si el escenario no puede tolerar el procesamiento duplicado, entonces hará falta lógica adicional en la aplicación para detectar duplicados. Esto se puede conseguir basándose en la propiedad MessageId del mensaje. El valor de esta propiedad permanece constante en los intentos de entrega. Esto se denomina procesamiento Una sola vez.

El código que se muestra aquí ilustra cómo recibir y procesar un mensaje mediante el modo PeekLock, que es el modo predeterminado si no se proporciona un valor de ReceiveMode de forma explícita.

MessageReceiver receiver = factory.CreateMessageReceiver("DataCollectionQueue");
BrokeredMessage receivedMessage = receiver.Receive();
try
{
    ProcessMessage(receivedMessage);
    receivedMessage.Complete();
}
catch (Exception e)
{
    receivedMessage.Abandon();
}

En los ejemplos anteriores de esta sección, creamos objetos MessageSender y MessageReceiver directamente desde el MessagingFactory para enviar y recibir mensajes desde la cola, respectivamente. Un enfoque alternativo es utilizar la clase QueueClient, que admite tanto operaciones de envío como de recepción además de características más avanzadas como sesiones.

QueueClient queueClient = 
     factory.CreateQueueClient("DataCollectionQueue");
queueClient.Send(bm);
            
BrokeredMessage message = queueClient.Receive();
try
{
    ProcessMessage(message);
    message.Complete();
}
catch (Exception e)
{
    message.Abandon();
} 

Mostrar:
© 2014 Microsoft