1

I have an azure function that reads from a ServiceBus topic and calls a 3rd party service. If the service is down, I would like to wait 5 minutes before trying to call it again with the same message. How can I add a delay so the azure function doesn't abandon the message and immediately pick it back up again?

public static void Run([ServiceBusTrigger("someTopic", 
     "someSubscription", AccessRights.Manage, Connection = 
     "ServiceBusConnection")] BrokeredMessage message) 
{
     CallService(bodyOfBrokeredMessage); //service is down

     //How do I add a delay so the message won't be reprocessed immediately thus quickly exhausting it's max delivery count?
}
Jayendran
  • 9,638
  • 8
  • 60
  • 103
TheEmirOfGroofunkistan
  • 5,476
  • 8
  • 37
  • 53

3 Answers3

3

One option is to create a new message and submit that message to the queue but set the ScheduledEnqueueTimeUtc to be five minutes in the future.

        [FunctionName("DelayMessage")]
        public static async Task DelayMessage(
            [ServiceBusTrigger("MyQueue", AccessRights.Listen, Connection = "MyConnection")]BrokeredMessage originalMessage,
            [ServiceBus("MyQueue", AccessRights.Send, Connection = "MyConnection")]IAsyncCollector<BrokeredMessage> newMessages,
            TraceWriter log)
        {
            //handle any kind of error scenerio

            var newMessage = originalMessage.Clone();

            newMessage.ScheduledEnqueueTimeUtc = DateTime.UtcNow.AddMinutes(5);

            await newMessages.AddAsync(newMessage);

        }
Josh Carlisle
  • 587
  • 2
  • 6
1

You can now use the fixed delay retry, which was added to Azure Functions around November 2020 (preview).

[FunctionName("MyFunction")]
[FixedDelayRetry(10, "00:05:00")]   // retries with a 5-minute delay
public static void Run([ServiceBusTrigger("someTopic", 
     "someSubscription", AccessRights.Manage, Connection = 
     "ServiceBusConnection")] BrokeredMessage message) 
{
     CallService(bodyOfBrokeredMessage); //service is down
}
Douglas
  • 53,759
  • 13
  • 140
  • 188
0

As Josh said, you could simply clone the original message, set up the scheduled enqueue time, send the clone and complete the original.

Well, it’s a shame that sending the clone and completing the original are not an atomic operation, so there is a very slim chance of us seeing the original again should the handling process crash at just the wrong moment.

And the other issue is that DeliveryCount on the clone will always be 1, because this is a brand new message. So we could infinitely resubmit and never get round to dead-lettering this message.

Fortunately, that can be fixed by adding our own resubmit count as a property of the message:

[FunctionName("DelayMessage")]
public static async Task DelayMessage([ServiceBusTrigger("MyQueue", AccessRights.Listen, Connection = "MyConnection")]BrokeredMessage originalMessage,
            [ServiceBus("MyQueue", AccessRights.Send, Connection = "MyConnection")]IAsyncCollector<BrokeredMessage> newMessages,TraceWriter log)
{
     //handle any kind of error scenerio
     int resubmitCount = originalMessage.Properties.ContainsKey("ResubmitCount") ?  (int)originalMessage.Properties["ResubmitCount"] : 0;
     if (resubmitCount > 5)
     {
         Console.WriteLine("DEAD-LETTERING");
         originalMessage.DeadLetter("Too many retries", $"ResubmitCount is {resubmitCount}");
     }
     else
     {
         var newMessage = originalMessage.Clone();
         newMessage.ScheduledEnqueueTimeUtc = DateTime.UtcNow.AddMinutes(5);
         await newMessages.AddAsync(newMessage);
     }
}

For more details, you could refer to this article.

Also, it's quite easy to implement the wait/retry/dequeue next pattern in a LogicApp since this type of flow control is exactly what LogicApps was designed for. Please refer to this SO thread.

Joey Cai
  • 18,968
  • 1
  • 20
  • 30
  • While not exactly what I was hoping for, this works for my use case. Thanks. Also, you have a small copy/paste typo in the code (int)m.Properties["ResubmitCount"] – TheEmirOfGroofunkistan Sep 06 '18 at 17:42