We are using Service Bus Topic Trigger Azure function, and we're planning to implement a simple behavior in Azure Function, if there is any exception during processing/handling we want to postpone the next retry from some time.
Currently we're planning to use [ExponentialBackoffRetry]
attribute, as shown in the below code.
But Can we use Polly retry instead of [ExponentialBackoffRetry]
? Basically which approach would be idle for our requirement - [ExponentialBackoffRetry]
or Polly retry
Below is our Service Bus Topic Trigger Azure Function:
[FunctionName(nameof(CardGroupEventSubscriber))]
[ExponentialBackoffRetry(5, "00:00:04", "00:01:00")]
public async Task RunAsync([ServiceBusTrigger("%ServiceBusConfigOptions:TopicEventTypeName%", "%ServiceBusConfigOptions:TopicEventTypeSubscription%",
Connection = "ServiceBusConfigOptions:ConnectionString")]
string sbMsg)
{
try
{
var message = sbMsg.AsPoco<CardGroupEvent>();
_logger.LogInformation("{class} - {method} - {RequestId} - Start",
nameof(CardGroupEventSubscriber), nameof(CardGroupEventSubscriber.RunAsync), message.RequestID);
_logger.LogInformation($"Started processing message {message.AsJson()} with", nameof(CardGroupEventSubscriber));
var validationResult = new CardGroupEventValidator().Validate(message);
if (validationResult.IsValid)
{
await _processor.ProcessAsync(message);
}
catch (Exception ex)
{
_logger.LogError($"Unable to process card group event {sbMsg.AsJson()} with {nameof(CardGroupEventSubscriber)}," +
$" ExceptionMessage:{ex.Message}, StackTrace: {ex.StackTrace}");
throw;
}
#endregion
}
Polly's policies can be defined and used in an imperative way.
Whereas the ExponentialBackoffRetry
attribute can be considered as declarative.
So, let's say you want to define a policy which
CosmosException
is thrown then you do that like this:const int maxRetryAttempts = 10;
const int maxDelayInMilliseconds = 32 * 1000;
var jitterer = new Random();
var policy = Policy
.Handle<CosmosException>()
.WaitAndRetryAsync(
maxRetryAttempts,
retryAttempt =>
{
var calculatedDelayInMilliseconds = Math.Pow(2, retryAttempt) * 1000;
var jitterInMilliseconds = jitterer.Next(0, 1000);
var actualDelay = Math.Min(calculatedDelayInMilliseconds + jitterInMilliseconds, maxDelayInMilliseconds);
return TimeSpan.FromMilliseconds(actualDelay);
}
);
Polly.Contrib.WaitAndRetry
) Now let's apply this to your RunAsync
method
[FunctionName(nameof(CardGroupEventSubscriber))]
public async Task RunAsync([ServiceBusTrigger("%ServiceBusConfigOptions:TopicEventTypeName%", "%ServiceBusConfigOptions:TopicEventTypeSubscription%",
Connection = "ServiceBusConfigOptions:ConnectionString")]
string sbMsg)
=> await GetExponentialBackoffRetryPolicy.ExecuteAsync(
async () => await RunCoreAsync(sbMsg));
public async Task RunCoreAsync(string sbMsg)
{
try
...
}
RunAsync
's code into the RunCoreAsync
methodRunAsync
implementation with a one liner which creates the above policy then decorates the RunCoreAsync
Just a side note: In case of CosmosDb it might make sense to handle the rate limiting/throttling in a different way.
When I receive a CosmosException
and the StatusCode
is 429 then use the RetryAfter
's Value to delay the retry, something like this
var policy = Policy
.Handle<CosmosException>(ex => ex.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(maxRetryAttempts,
sleepDurationProvider:(_, ex, __) => ((CosmosException)ex).RetryAfter.Value,
onRetryAsync: (_, __, ___, ____) => Task.CompletedTask);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.