Azure Service Bus .NET SDK Deep Dive – Connections

Explains connections and how they relate to senders and receivers, for more posts in this series go to Contents.

So far, we’ve been creating QueueClients to send and receive messages. We’ve also learned that we can leverage MessageSenders and MessageReceivers to abstract our code slightly from the actual entity in use. The below code illustrates a small example that sends a message to a destination and then receives a single message from that destination.

var sender = new MessageSender(connectionString, destination);
await sender.SendAsync(new Message(Encoding.UTF8.GetBytes("Deep Dive")));
var receiver = new MessageReceiver(connectionString, destination);
await receiver.ReceiveAsync();

The common thing that we’ve seen in the samples so far as well as in the code above is that we are using a constructor that accepts a connection string to Azure Service Bus. Let’s explore what happens under the hood with netstat while the above sample code is running:

netstat -na | find "5671"
  TCP    192.168.1.7:59350      52.166.127.37:5671     ESTABLISHED
  TCP    192.168.1.7:59352      52.166.127.37:5671     ESTABLISHED

By creating senders and receivers with the overload that accepts a connection string a dedicated connection is established per instance. It is possible to verify that hypothesis by adding an additional sender:

var sender1 = new MessageSender(connectionString, destination);
var sender2 = new MessageSender(connectionString, destination);
await sender1.SendAsync(new Message(Encoding.UTF8.GetBytes("Deep Dive")));
await sender2.SendAsync(new Message(Encoding.UTF8.GetBytes("Deep Dive")));
var receiver = new MessageReceiver(connectionString, destination);
await receiver.ReceiveAsync();

and indeed we have three established connections.

netstat -na | find "5671"
  TCP    192.168.1.7:59724      52.166.127.37:5671     ESTABLISHED
  TCP    192.168.1.7:59726      52.166.127.37:5671     ESTABLISHED
  TCP    192.168.1.7:59728      52.166.127.37:5671     ESTABLISHED

But there is more. The Azure Service Bus SDK allows us to separate the connection management from the senders and receivers. Sometimes it makes sense to gain more control over when a connection is established and whether an existing connection should be reused across instances (for example, to be able to easily create cheap senders and receivers but keep the more expensive connection alive for longer). If fine-grained control is required, it is possible to create a ServiceBusConnection object and pass it to the senders and receivers.

var connection = new ServiceBusConnection(connectionString);
var sender = new MessageSender(connection, destination);
var receiver = new MessageReceiver(connection, destination);

await sender.SendAsync(new Message(Encoding.UTF8.GetBytes("Deep Dive")));
await receiver.ReceiveAsync();

Let’s consult our good old netstat while the above code is running:

netstat -na | find "5671"
  TCP    192.168.1.7:60470      52.166.127.37:5671     ESTABLISHED

Now only the existing already established connection is used and we can create senders and receivers without paying the overhead of re-initiating the connection all the time. Before you jump too early conclusions and think you are only going to use the connection sharing approach, I suggest you carefully think about usage patterns you are anticipating. Measure it with a realistic load, which makes the most sense for your application or system.

About the author

Daniel Marbach

1 comment

By Daniel Marbach

Recent Posts