Service Bus –Complete Message Asynchronously or Synchronously?
Published Feb 05 2021 12:57 AM 15.5K Views
Microsoft

As we know there are two kinds of operations for program threads --- Asynchronous and Synchronous. 

These are the definitions we can get from internet. 

Asynchronous operation means the process operates independently of other processes.  

Synchronous operation means the process runs only as a resource or some other process being completed or handed off.  

However, whether it’s good to Receive Message Asynchronously on the Azure Service Bus?  

Pre-requirement 

Before we start, please read these documents. Service Bus asynchronous messaging and Azure Service Bus messaging receive mode 

From the above pre-requisites, we learn the following: 

Azure Service Bus support both Asynchronous messaging patterns and Synchronous messaging patterns. Applications typically use asynchronous messaging patterns to enable several communication scenarios. 

This test is archived based on Service Bus PeekLock Receive mode. Here is more background information about the principle for PeekLock receive mode.  

The principle for PeekLock Receive mode is that: 

  • Every time the Service Bus finds the next message to be consumed. 
  • Locks it to prevent other consumers from receiving it. 
  • Then, return the message to the application.  

There is a common exception for the Service Bus Lock expiration. This exception is because the message transaction time longer than Lock duration. It may be due to many reasons like Receive Application has high latency. This blog will also reproduce this Lock expired exception for Receive Messages Asynchronously and Synchronously. Let's do a test now 

Test Entities: 

I use a same Queue to do this test. The Max delivery count is 1 If you are interested about the usage of “Max delivery count” please check from here Service Bus exceeding MaxDeliveryCount 

Message lock duration time is 30s.  

Scarlett_liu_0-1611052688610.jpeg

My Program: 

Here I use different function in .Net for receive messages. All the functions have Async” like ReceiveBatchAsync means the functions are working Asynchronously. 

 

To simulate the situation by sending a large number of messages, I received 5000 messages at one operation. 

 

  • Here is the program that complete messages in Asynchronous patterns.  

using Microsoft.ServiceBus.Messaging; 

using System; 

using System.Collections.Generic; 

using System.Linq; 

using System.Text; 

using System.Threading.Tasks; 

 

namespace SendReceiveQueue 

{ 

    class Program 

    { 

        static string connectionString = "<your connection string>"; 

        static string queueName = "<queue name>"; 

        static void Main(string[args) 

        { 

            MainAsync().GetAwaiter().GetResult(); 

        } 

        public static async Task MainAsync() 

        { 

            QueueClient receiveClient = QueueClient.CreateFromConnectionString(connectionStringqueueName); 

            //create a sender on the queue 

            var Timestamp2 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 

            Console.WriteLine("Receiving message -, timestamp:{0}", Timestamp2); 

 

 

             IEnumerable<BrokeredMessagemessageList = await receiveClient.ReceiveBatchAsync(5000); 

            foreach (BrokeredMessage message in messageList) 

            { 

                try 

                { 

                    var Timestamp0 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 

                    Console.WriteLine("Message"+message.GetBody<string>() +"time"+Timestamp0); 

 

                    message.CompleteAsync(); 

                } 

                catch (Exception ex) 

                { 

                    var Timestamp3 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 

                    Console.WriteLine("abandon message - timestamp:{0},errorr message {1}", Timestamp3,ex.Message); 

                    await message.AbandonAsync(); 

                } 

            } 

 

            await receiveClient.CloseAsync(); 

        } 

    } 

} 

 

This is the result. The average time of receiving message is in 200ms to 300ms. 

Scarlett_liu_1-1611052688631.jpeg

  • And this is the Code for receiving messages with Synchronous messaging patterns.  

using Microsoft.ServiceBus.Messaging; 

using System; 

using System.Collections.Generic; 

using System.Linq; 

using System.Text; 

 

 

namespace SendReceiveQueue 

{ 

    class Program 

    { 

        static string connectionString = "<your connection string>"; 

        static string queueName = "<queue name>"; 

        static void Main(string[args) 

        { 

            MainTest(); 

        } 

        static void MainTest() 

        { 

            QueueClient receiveClient = QueueClient.CreateFromConnectionString(connectionStringqueueName); 

            //create a sender on the queue 

            var Timestamp2 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 

            Console.WriteLine("Receiving message -, timestamp:{0}", Timestamp2); 

 

            IEnumerable<BrokeredMessagemessageList = receiveClient.ReceiveBatch(5000); 

            foreach (BrokeredMessage message in messageList) 

            { 

                try 

                { 

                    var Timestamp0 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 

                    Console.WriteLine("Message" + message.GetBody<string>() + "time" + Timestamp0); 

 

                    message.Complete(); 

                } 

                catch (Exception ex) 

                { 

                    var Timestamp3 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 

                    Console.WriteLine("abandon message - timestamp:{0},errorr message {1}", Timestamp3, ex.Message); 

                    message.Abandon(); 

                } 

            } 

 

            receiveClient.Close(); 

            Console.Read(); 

        } 

    } 

} 

 

This is the result. At first time the messages can also finish in 200ms to 300ms. But after a while It shows error for “lock expired”.  

Scarlett_liu_2-1611052688638.jpeg

Why didn’t we get any errors while using the Async pattern in this program? Why we got “Lock expired” exception while using Sync pattern 

This exception is highly possible in receiving messages in one operation. Using Peeklock receive mode, Service Bus locked all the 5000 messages at the same time. And then complete messages in Asynchronous pattern, Messages can be completed without blocking 

But using Synchronous pattern, all the Messages was completed one by one, the waiting time exceeds 30s. So, it shows “lock expired” error.  

You can get detailed information on how the asynchronous C# backend works from this document. Asynchronous programming in C# | Microsoft Docs 

 

Test Result Summary 

  • From the test result, it indicates that Asynchronous Messaging pattern is more efficient since it will return immediatelyWe recommend using Asynchronous over than Synchronous. 
  • As mentioned before this “Lock expired” exception may be due to many reasons. That also the reason Service Bus have Dead Lettering Queue to prevent Service Bus message being lost. If you are interested in this topic, you are welcome to provide your comments.  
Co-Authors
Version history
Last update:
‎Feb 05 2021 12:53 AM
Updated by: