3

I am writing some code to monitor our azure servicebus queues and topics, I want to notify if we have old messages. My code works except that, if a subscription does not have any active messages in it, then it will hang for one minute and then throw an exception that says:

Unhandled exception. Azure.Messaging.ServiceBus.ServiceBusException: The operation did not complete within the allocated time 00:01:00 for object receiver12. (ServiceTimeout)
---> System.TimeoutException: The operation did not complete within the allocated time 00:01:00 for object receiver12.

Looks like it only happens on session enabled subscriptions. I have tried to first look if there are any messages in the subscription and if so, peek them, but often the messages will be received between I check messages count and the peek so the exception occurs. My monitoring solution does not handle that long timeout. I would just like to retrieve and empty list if the subscription is empty. Have also tried the python implementation and it is the same so there must be something fundamental that I don't get.

Some code:

using Azure.Messaging.ServiceBus;

string connectionString = "Endpoint=sb://xxxxxxxx";
string topicName = "topic";
string subscriptionName = "subscription";


await using var client = new ServiceBusClient(connectionString);

// Exception if subscription does not have any active messages...
ServiceBusSessionReceiver receiver = await client.AcceptNextSessionAsync(topicName, subscriptionName);

// Peek messages
IReadOnlyList<ServiceBusReceivedMessage> peekedMessages = await receiver.PeekMessagesAsync(10);

foreach (ServiceBusReceivedMessage peekedMessage in peekedMessagesFiltered)
{
    Console.WriteLine(peekedMessage.EnqueuedTime.ToString());

}
Clint Eastwood
  • 165
  • 3
  • 10

2 Answers2

0
  • The idea for TimeoutExceptions is to include retries, which should already be happening. These exceptions from log entries should be transient in nature, and your Function should recover and continue to run.
  • The server failed to respond to the requested operation within the time period specified, which is controlled by OperationTimeout. The requested operation may have been completed by the server. Delays in the network or other infrastructure might cause this.
  • To avoid such behaviour, you should implement the retry logic.
    Reference doc: Service Bus messaging exceptions
  • Please see the following link for further information on exception types and how to handle them properly http://go.microsoft.com/fwlink/?LinkId=761101
  • Check the value of the ServicePointManager.DefaultConnectionLimit property, as exceeding it limit may result in a TimeoutException.
  • References - link1, link2, link3
  • 2
    I have this issues 100% of the times when peeking a subscription with sessions enabled that does not have any active messages. It is not just random network issues. – Clint Eastwood Apr 08 '22 at 07:32
  • Can you share the full stack trace for the exception? ServiceTimeout is expected when attempting to accept the next session if there are no sessions, but not when peeking. I tried to repro this, and I always get pack an empty list rather than hitting an exception when peeking a session subscription with no messages. – Josh Love Jun 10 '22 at 05:08
  • Seeing the same issue. Still not found a valid solution. – Peter Dec 22 '22 at 13:58
  • Have you @ClintEastwood found an way to handle/resolve this? – Peter Dec 22 '22 at 17:10
  • 1
    @Peter Did not solve it, Handeled it by first polling message count and if that is more than 0, then I would peek. It is not accurate though, messages can get handled between checking count and actually peeking. Also, Instead of our monitoring system checking directly I have a cronjob storing the result i a JSON-file which mon sys is checking instead. Also switched to python, think this is the equivalent function: https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.servicebus.management.managementclient.getsubscriptionruntimeinfoasync?view=azure-dotnet So need azure cred as well. – Clint Eastwood Dec 24 '22 at 14:44
0

** DISCLAIMER ** Not best practice to catch an exception this way and not use it.

Wrapping it in a try catch block, gives us the opportunity to retry.

I would also wrap it in a loop, so it would return and pick up a new session of messages. If not anyone else can make a better answer for this, I hope this helps some.

the closeAsync() is for disposing the receiver.

    using Azure.Messaging.ServiceBus;
    
    string connectionString = "Endpoint=sb://xxxxxxxx";
    string topicName = "topic";
    string subscriptionName = "subscription";
    
    
    await using var client = new ServiceBusClient(connectionString);
    do
    {
      // Exception if subscription does not have any active messages...
      ServiceBusSessionReceiver receiver = await client.AcceptNextSessionAsync(topicName, subscriptionName);
      try
      {

          // Peek messages
          IReadOnlyList<ServiceBusReceivedMessage> peekedMessages = await receiver.PeekMessagesAsync(10);
    
          foreach (ServiceBusReceivedMessage peekedMessage in peekedMessagesFiltered)
          {
            Console.WriteLine(peekedMessage.EnqueuedTime.ToString());
    
          }
            await reciver.CloseAsync();
        }
        catch (ServiceBusException ex)
        {
          Log.Logger.Warning($"Timeout exception caught: {ex.Message}", ex);
        }
     } while (true)
Peter
  • 104
  • 1
  • 6