Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reusing Connections in Azure Service Bus

We have an API hosted on Windows Azure in a web role with 2 instances that takes in requests, validates them then adds them to an Azure Service Bus Queue.

Recently we've started load testing this and found that our current code throws the below exception:

Could not add command to the command queue Exception: Microsoft.ServiceBus.Messaging.QuotaExceededException: The number of maximumallowed connections have been reached or exceeded for Queue Number of active connections: 100, Maximum allowed connections: 100.

Would the below client code keep a single connection open assuming we maintained a single instance of the class? I am trying to ascertain whether the issue is with ServiceBusClient code or our dependency registration initialising a new client for each request.

public class ServiceBusClient : IDisposable
{
    #region Constants and Fields

    protected readonly NamespaceManager NamespaceManager;

    private const int DEFAULT_LOCK_DURATION_IN_SECONDS = 300; // 5 minutes 

    private const string SERVICE_BUS_CONNECTION_STRING_KEY 
                            = "service.bus.connection.string";

    private readonly IMessageBodySerializer _messageBodySerializer;

    private readonly MessagingFactory _messagingFactory;

    private readonly QueueClient _queueClient;

    private readonly string _queueName;

    private readonly ISettingsManager _settingsManager;

    #endregion

    #region Constructors and Destructors

    public ServiceBusClient(
        ISettingsManager settingsManager, 
        IMessageBodySerializer messageBodySerializer, s
        tring queueName)
    {
        _settingsManager = settingsManager;
        _messageBodySerializer = messageBodySerializer;

        var connectionString = _settingsManager.GetSetting<string>(
            SERVICE_BUS_CONNECTION_STRING_KEY);

        NamespaceManager = 
            NamespaceManager.CreateFromConnectionString(connectionString);

        _messagingFactory = 
            MessagingFactory.CreateFromConnectionString(connectionString);

        _queueName = queueName;
        _queueClient = GetOrCreateQueue();
    }

    #endregion

    #region Public Methods and Operators

    public virtual void SendMessage(object bodyObject)
    {
        var brokeredMessage = 
            _messageBodySerializer.SerializeMessageBody(bodyObject);

        _queueClient.Send(brokeredMessage);
    }

    public void Dispose()
    {
        _messagingFactory.Close();
    }

    #endregion

    #region Methods

    private QueueClient GetOrCreateQueue()
    {
        QueueDescription queue;

        if (!NamespaceManager.QueueExists(_queueName))
        {
            var queueToCreate = new QueueDescription(_queueName)
            {
                LockDuration = TimeSpan.FromSeconds(
                    DEFAULT_LOCK_DURATION_IN_SECONDS)
            };

            queue = NamespaceManager.CreateQueue(queueToCreate);
        }
        else
        {
            queue = NamespaceManager.GetQueue(_queueName);
        }

        return _messagingFactory.CreateQueueClient(
                        queue.Path, 
                        ReceiveMode.PeekLock);
    }

    #endregion
}

As an extension to this; if the above code does keep an active connection open; would using the singleton pattern to store an instance of the ServiceBusClient for each instance of the API be dangerous? Or does the Azure SDK handle closed connections internally?

like image 757
Luke Merrett Avatar asked Dec 25 '22 23:12

Luke Merrett


1 Answers

From a connection management perspective, following may be helpful:

1) A single connection is created for a MessagingFactory instance

2) You can create as many QueueClient instances from a single MessagingFactory but they will all use the same actual underlying TCP connection, so consider throughput and availability here because more connections can help

3) We will reconnect the underlying connection for a MessagingFactory in case it is dropped

4) From a QueueClient perspective you are creating connections to a particular Queue, consider these links (several of these can exist over a single MessagingFactory connection). Again if the connection is dropped it will be recreated and so will be the links for the Queues, you do not need to recreate the objects

5) The Quota of 100 concurrent connections is imposed on a per Queue basis so essentially you can have up to 100 links to a single Queue

6) These are not impacted by how many MessagingFactory instances you create these links over

7) If you call close/dispose on the MessagingFactory then all the links over that connection will be closed too and will not reconnect

like image 187
Abhishek Lal Avatar answered Jan 14 '23 16:01

Abhishek Lal