I need to handle list of exception in generic way. I need to rewrite the code in Polly style.
I have existing working code where custom generic exception handled:
readonly TimeSpan maxDelay;
readonly int initialRetryDelayInMilliseconds;
readonly double backoffFactor;
readonly int maxAttemptCount;
readonly string methodName;
readonly List<Exception> allowedExceptions;
public ExponentialBackoffService(string _methodName,int _initialRetryDelayInMilliseconds, TimeSpan _maxDelay, double _backoffFactor, int _maxAttemptCount, List<Exception> _allowedExceptions = null)
{
initialRetryDelayInMilliseconds = _initialRetryDelayInMilliseconds;
backoffFactor = _backoffFactor;
maxAttemptCount = _maxAttemptCount;
maxDelay = _maxDelay;
methodName = _methodName;
allowedExceptions = _allowedExceptions;
}
public virtual async Task<T> Do<T>(Func<Task<T>> task)
{
TraceLogger.Log("ExponentialBackoffService", 0, "ExponentialBackoffService task do", true);
var exceptions = new List<Exception>();
for (int attempted = 0; attempted < maxAttemptCount; attempted++)
{
var trace = TraceLog.GenerateTraceLog($"ExponentialBackoffService call started==>{attempted}");
trace.Category = "ExponentialBackoffService";
await Logger.WriteLogAsync(trace);
try
{
if (attempted > 0)
{
TimeSpan retryDelayInMilliseconds = CalculateExponentialBackoff(TimeSpan.FromMilliseconds(initialRetryDelayInMilliseconds), attempted);
await Task.Delay(retryDelayInMilliseconds);
await Logger.WriteLogAsync(GenerateTrace(retryDelayInMilliseconds));
}
return await task();
}
catch (Exception ex)
{
if (AllowAllException() || AllowSpecificExceptions(ex))
{
exceptions.Add(ex);
}
else { throw; }
}
finally
{
var trace1 = TraceLog.GenerateTraceLog($"ExponentialBackoffService call completed==>{attempted}");
trace1.Category = "ExponentialBackoffService";
await Logger.WriteLogAsync(trace1);
}
}
throw new AggregateException(exceptions);
}
public virtual bool AllowAllException()
{
return allowedExceptions == null || allowedExceptions?.Count() == 0;
}
public virtual bool AllowSpecificExceptions(Exception currentException)
{
bool isCurrentExceptionAllowed = false;
if(allowedExceptions?.Count() > 0)
{
foreach (Exception exception in allowedExceptions)
{
if(exception.GetType()== currentException.GetType())
{
isCurrentExceptionAllowed = true;
break;
}
}
return isCurrentExceptionAllowed;
}
return true;
}
Need to rewrite the above code in polly style.
1st question
var existingPolicy = Policy.WaitAndRetryAsyc(BackOff.DecorrletedJitterBackOffV2)
Here,need to define retry logic and logging for each retry; no exception definition
2nd question
if(allowedExceptions?.Count() > 0)
{
for(int i ;i<allowedExceptions.count();i++)
{
var dynamicPolicy=Policy.Handle<allowedExceptions[i].GetType>;//create dynamic policy for handle exception
existingPolicy.WrapAsync(dynamicPolicy);//appending each exception as per exceptionList
}
}
According to caller , will send a list of exception, those generic exceptions need to be added in the policy
And last execute
existingPolicy.executeAsync(task);
Let me first try to reply to your second question.
Since your
allowedExceptions
is aList<Exception>
that's why you can write this:or simply just
In both cases you define a policy which should trigger only if an exception is thrown and that exception is one of the allowed exceptions.
Now let's focus on your first question.
In case of Polly V7 you can define a policy which should trigger either if a specific exception is thrown (
Handle<TEx>
/HandleInner<TEx>
) or the result object is in a given state (HandleResult<TResult>(Predicate p)
).So, if you want to retry n times unconditionally then you can do the following workaround:
That means your to-be-decorated method needs to return either with a reference type instance or a null.
Or you can define the trigger for
bool
:It's up to you which one do you prefer. It's a workaround because Polly V7 does not support unconditional triggering.