Skip Navigation LinksWindows Azure Service Bus Developer Guide > Brokered Messaging > Using Queues > Receiving Messages

Train with Alan
Alan Smith
Email: cloudcasts.net@gmail.com Blog: geekswithblogs.net/asmith Twitter: @alansmith Linked In: Alan Smith

Receiving Messages

Messages can be received from queues or subscriptions and the same techniques are used for both scenarios. The MessageReceiver class is used internally by the QueueClient and SubscriptionClient classes for receiving messages. Messages can also be received as sessions using the MessageSession class, which derives from MessageReceiver.

There are three techniques that can be used for receiving messages.

·        Receive and Delete Receive Mode

·        Peek Lock Receive Mode

·        Transactional Receives

 

Receive and Delete Receive Mode

The receive and delete mode is the simplest way of receiving messages from a queue. When using this mode messages will be received from the queue and marked as complete in one operation, causing them to be deleted from the queue. Although this is the simplest way of receiving messages it is not the most optimal. If the receiving application fails to process the message successfully it will be lost. Once a message is received using this mode it is not possible to defer, dead-letter or abandon processing of the message. Using the receive and delete mode provides at-least-once processing semantics.

The following code shows how to create a queue client using the receive and delete receive mode, and then receive any messages that are on the queue.

 

// Use the MessagingFactory to create a queue client for the orderqueue.

QueueClient queueClient = factory.CreateQueueClient

    ("orderqueue", ReceiveMode.ReceiveAndDelete);

 

// Receive messages from the queue with a 10 second timeout.

while (true)

{

    // Receive a message using a 10 second timeout

    BrokeredMessage msg = queueClient.Receive(TimeSpan.FromSeconds(10));

 

    if (msg != null)

    {

        // Deserialize the message body to an order data contract.

        Order order = msg.GetBody<Order>();

 

        // Output the order.

        Console.WriteLine("{0} {1} {2} {3} {4} ${5}",

            order.OrderNumber,

            order.Customer.FirstName,

            order.Customer.LastName,

            order.ShipTo.City,

            order.ShipTo.Province,

            order.Total);

    }

    else

    {

        // No message has been received, we will poll for more messages.

        Console.WriteLine("Polling, polling, polling...");

    }

}

 

 

Peek Lock Receive Mode

The peak-lock receive mode uses a two-phase protocol to receive messages from queues and subscriptions. It is the default receive mode for queue and subscription clients. When a message is received it is placed into a locked state on the queue and will remain in that state until the state is changed, or a lock timeout occurs, at which point it will become visible again.

Whilst the message is in the locked state the receiving application can perform one, and only one, of the following actions.

·        Complete – The message is marked as complete; this should be done when the message has been processed successfully.

·        Abandon – The message is unlocked and available for receiving again, this should be done when the processing of a message has failed and the failure was not due to the message content.

·        Defer – The message remains on the queue in a deferred state and can be received at a later point in time using the message sequence id. This should be done when a receiving application will process the message at a later point in time.

·        DeadLetter – The message is places on a deadletter sub-queue and can be received and processed at a later point in time. This should typically be done when the processing of a message has failed due to the message content.

The following code shows how a message can be received using the default peek lock receive mode, and then completed if processed successfully, or abandoned if an error occurred adding the order to the database.

 

// Use the MessagingFactory to create a queue client for the orderqueue.

QueueClient queueClient = factory.CreateQueueClient("orderqueue");

 

 

// Receive messages from the queue with a 10 second timeout.

while (true)

{

    // Receive a message using a 10 second timeout

    BrokeredMessage msg = queueClient.Receive(TimeSpan.FromSeconds(10));

 

    if (msg != null)

    {

        // Deserialize the message body to an order data contract.

        Order order = msg.GetBody<Order>();

 

        // Output the order.

        Console.WriteLine("{0} {1} {2} {3} {4} ${5}",

            order.OrderNumber,

            order.Customer.FirstName,

            order.Customer.LastName,

            order.ShipTo.City,

            order.ShipTo.Province,

            order.Total);

 

        // Update the database

        try

        {

            // Add the order to the database.

            OrdersData.AddOrder(order);

 

            // Mark the message as complete.

            msg.Complete();

        }

        catch (Exception ex)

        {

            Console.WriteLine("Exception: {0}", ex.Message);

 

            // Something went wrong, abandon the message.

            msg.Abandon();

        }

    }

    else

    {

        // No message has been received, we will poll for more messages.

        Console.WriteLine("Polling, polling, polling...");

    }

}

 

 

Note that the above solution could fail repeatedly for the same message if something in the content of the message was causing the exception when adding the order to the database. If this was to happen the message would automatically be deadlettered when the DeliveryCount of the message reached the MaxDeliveryCount of the queue. The default MaxDeliveryCount for a queue is 10.

 

Received Message Lock Timeout

The lock timeout is set on the queue as the LockDuration property, and has a default value of 60 seconds and a maximum value of 5 minutes. Unlike Azure Storage queues it is not possible for a receiving application to specify a value for the lock timeout when receiving a massage, nor is it possible to change the LockDuration property on a queue once it has been created. Care should be taken when deciding on a value for the LockDuration property of a queue created for use in production systems as it can have significant impact on the processing of messages in receiving applications.

If the processing time of a message in a receiving application exceeds the lock timeout, the message will become visible to other applications, and data duplication can occur if messages are processed more than once. An exception will be thrown in the receiving application if it attempts to call complete on a message when the lock timeout has expired. The receiving application can check when the lock timeout expires by checking the LockedUntilUtc property of the received message. Bear in mind that this property will be based on the setting of UTC time at the Azure data center, and there may be a slight time difference between that time and the time on the computer hosting the receiving application.

Poison Messages

If a message is received using peek-lock mode and the processing of the message fails the receiving application can call the Abandon message to release the lock and make it available for receiving again. If there is something about that particular message that is causing processing to fail the message will be stuck in an endless loop, and will be received and abandoned multiple times. Messages that cause this kind of failure are known as poison messages, and receiving applications should include the capability to identify and handle them accordingly.

The BrokeredMessage class provides a DeliveryCount property that identifies the number of times a message has been received from a queue or subscription. A receiving application could have a delivery count threshold where any message received with a DeliveryCount greater than that value is assumed to be a poison message, and can be placed on a dead-letter queue. The queue also contains a MaxDeliveryCount property that can automatically deadletter messages that have been received a specified number of times.