Problems with high availability of ServiceBus 1.1 for Windows Server

There are some interesting behavior SB high availability. Let’s look into the following scenario: 

  • A typical ServiceBus farm with 3 hosts.
  • Use the connection string returned by get-SBClientConfiguration which includes all the 3 hosts.
  • The first host in the connection string is stopped.

 
 
  
    

In this case, when connect with ServiceBus Explorer 2.1.3, it will always fail on GetQueues().

 

 

In below sample, if OperationTimeout is set to a pretty long value, the built-in retry policy will be able to allow my client code to switch to a running host and properly send/receive the message before timeout occurs.

 

I set OperationTimeout to 90 seconds and this makes the code execute successfully for most of cases. However, if I reduce the timeout settings, it either fails on QueueExists() or Send(). However increasing timeout is not a good enough solution because the overall performance will become very bad - the following code takes more than 1.5 min to finish.

 

So it will be ideal to find the approach to make it switch to a running host faster. The research is still in the process...

  using System; using Microsoft.ServiceBus; using Microsoft.ServiceBus.Messaging; public class Sender { static string[] ServerFQDN = new string[3]; static int HttpPort = 9355; static int TcpPort = 9354; static string ServiceNamespace = "ServiceBusDefaultNamespace"; static void Main(string[] args) { ServerFQDN[0] = "sbhost001.xxx.microsoft.com"; ServerFQDN[1] = "sbhost002.xxx.microsoft.com"; ServerFQDN[2] = "sbhost003.xxx.microsoft.com"; ServiceBusConnectionStringBuilder connBuilder = new ServiceBusConnectionStringBuilder(); connBuilder.ManagementPort = HttpPort; connBuilder.RuntimePort = TcpPort; for (int i = 0; i < 3; i++) { connBuilder.Endpoints.Add(new UriBuilder() { Scheme = "sb", Host = ServerFQDN[i], Path = ServiceNamespace }.Uri); connBuilder.StsEndpoints.Add(new UriBuilder() { Scheme = "https", Host = ServerFQDN[i], Port = HttpPort, Path = ServiceNamespace }.Uri); } NamespaceManager namespaceManager = NamespaceManager.CreateFromConnectionString(connBuilder.ToString()); namespaceManager.Settings.OperationTimeout = new TimeSpan(0, 0, 90); namespaceManager.Settings.RetryPolicy = RetryPolicy.Default; MessagingFactorySettings factorySetting = new MessagingFactorySettings(); factorySetting.OperationTimeout = TimeSpan.FromSeconds(90); factorySetting.TokenProvider = TokenProvider.CreateWindowsTokenProvider(connBuilder.StsEndpoints); factorySetting.EnableAdditionalClientTimeout = true; MessagingFactory messageFactory = MessagingFactory.Create(connBuilder.Endpoints, factorySetting); messageFactory.RetryPolicy = RetryPolicy.Default; if (namespaceManager == null) { Console.WriteLine("\nUnexpected Error"); return; } string QueueName = "ServiceBusQueueSample"; if (namespaceManager.QueueExists(QueueName)) { namespaceManager.DeleteQueue(QueueName); } namespaceManager.CreateQueue(QueueName); QueueClient myQueueClient = messageFactory.CreateQueueClient(QueueName); try { BrokeredMessage sendMessage = new BrokeredMessage("Hello World !"); myQueueClient.Send(sendMessage); // Receive the message from the queue BrokeredMessage receivedMessage = myQueueClient.Receive(TimeSpan.FromSeconds(5)); if (receivedMessage != null) { Console.WriteLine(string.Format("Message received: {0}", receivedMessage.GetBody<string>())); receivedMessage.Complete(); } } catch (Exception e) { Console.WriteLine("Unexpected exception {0}", e.ToString()); throw; } finally { if (messageFactory != null) messageFactory.Close(); } Console.WriteLine("Press ENTER to clean up and exit."); Console.ReadLine(); } } 

 

Best regards,

WenJun Zhang