This article is contributed. See the original author and article here.
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.
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 use Batch function to receive 1000 messages at one time.
- Here is the program that receives 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(connectionString, queueName);
//create a sender on the queue
var Timestamp2 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
Console.WriteLine(“Receiving message -, timestamp:{0}”, Timestamp2);
IEnumerable<BrokeredMessage> messageList = await receiveClient.ReceiveBatchAsync(1000);
foreach (BrokeredMessage message in messageList)
{
try
{
var Timestamp0 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
Console.WriteLine(“Message”+message.GetBody<string>() +“time”+Timestamp0);
await 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.
- 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(connectionString, queueName);
//create a sender on the queue
var Timestamp2 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
Console.WriteLine(“Receiving message -, timestamp:{0}”, Timestamp2);
IEnumerable<BrokeredMessage> messageList = receiveClient.ReceiveBatch(1000);
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”.
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 batch function. Because all these 1000 messages were received in one operation. Using Peeklock receive mode, Service Bus locked all the 1000 messages at the same time. And then complete messages in Asynchronous patten, Messages can be completed without blocking. The await keyword provides a non-blocking way to start a task, then continue execution when that task is completed. It saved the Message complete time.
But using Synchronous patten, 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 receiving messages with Asynchronous Messaging pattern would have higher ability than Synchronous Messaging pattern. We recommend using Asynchronous over than Synchronous.
- However, if we receive a larger number of messages in one Batch operation like 10000 messages. This program with Asynchronous Messaging pattern also would get “lock expired” error. 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.
Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.
Recent Comments