提问人:Sanman Chavan 提问时间:11/17/2023 最后编辑:Peter CsalaSanman Chavan 更新时间:11/20/2023 访问量:64
使用 polly 包处理异常列表的通用方法
Generic method which handles exception list with polly package
问:
我需要以通用方式处理异常列表。我需要以 Polly 风格重写代码。
我有处理自定义泛型异常的现有工作代码:
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;
}
需要以 polly 样式重写上面的代码。
第一个问题
var existingPolicy = Policy.WaitAndRetryAsyc(BackOff.DecorrletedJitterBackOffV2)
这里,需要定义每次重试的重试逻辑和日志记录;无异常定义
第二个问题
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
}
}
根据调用方,将发送异常列表,这些通用异常需要添加到策略中
最后执行
existingPolicy.executeAsync(task);
答:
-2赞
wpdnqd
11/17/2023
#1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Polly;
using Polly.Wrap;
public class ExponentialBackoffService
{
private readonly TimeSpan maxDelay;
private readonly int initialRetryDelayInMilliseconds;
private readonly double backoffFactor;
private readonly int maxAttemptCount;
private readonly string methodName;
private 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)
{
var retryPolicy = Policy.WrapAsync(CreateRetryPolicies());
try
{
return await retryPolicy.ExecuteAsync(task);
}
catch (AggregateException ex)
{
// Log aggregate exceptions
Console.WriteLine($"All retry attempts failed for {methodName}. Aggregating exceptions.");
throw;
}
}
private IEnumerable<IAsyncPolicy> CreateRetryPolicies()
{
var policies = new List<IAsyncPolicy>();
for (int i = 0; i < allowedExceptions?.Count; i++)
{
var exceptionType = allowedExceptions[i].GetType();
var dynamicPolicy = Policy.Handle(exceptionType)
.WaitAndRetryAsync(maxAttemptCount, attempt => CalculateExponentialBackoff(TimeSpan.FromMilliseconds(initialRetryDelayInMilliseconds), attempt),
(exception, timeSpan, retryCount, context) =>
{
// Log for each retry attempt
Console.WriteLine($"Retry attempt {retryCount} failed for {methodName}. Retrying in {timeSpan.TotalMilliseconds} ms.");
});
policies.Add(dynamicPolicy);
}
return policies;
}
private TimeSpan CalculateExponentialBackoff(TimeSpan initialDelay, int retryAttempt)
{
// Calculate exponential backoff with jitter
var delay = TimeSpan.FromMilliseconds(Math.Min(initialDelay.TotalMilliseconds * Math.Pow(backoffFactor, retryAttempt), maxDelay.TotalMilliseconds));
var jitter = new Random().Next(0, (int)(delay.TotalMilliseconds * 0.1)); // 10% jitter
return delay.Add(TimeSpan.FromMilliseconds(jitter));
}
}
评论
1赞
Sanman Chavan
11/17/2023
看来您只复制粘贴了问题
0赞
wpdnqd
11/17/2023
养成先阅读的习惯。
0赞
Sanman Chavan
11/17/2023
对不起,我的错。让我试试
0赞
Peter Csala
11/17/2023
@wpdnqd 此代码将无法编译。var dynamicPolicy = Policy.Handle(exceptionType)
2赞
BDL
11/17/2023
这个答案可能真的需要一些解释。
1赞
Peter Csala
11/17/2023
#2
让我先试着回答你的第二个问题。
既然你是,这就是为什么你可以这样写:allowedExceptions
List<Exception>
Policy.Handle<Exception>(ex => allowedExceptions.Contains(ex))
...
或者只是
Policy.Handle<Exception>(allowedExceptions.Contains)
...
在这两种情况下,您都定义了一个策略,该策略仅在引发异常时触发,并且该异常是允许的异常之一。
现在让我们关注你的第一个问题。
在 Polly V7 中,您可以定义一个策略,如果抛出特定异常 (/) 或结果对象处于给定状态 ()。Handle<TEx>
HandleInner<TEx>
HandleResult<TResult>(Predicate p)
因此,如果要无条件重试 n 次,则可以执行以下解决方法:
Policy.HandleResult<object?>(_ => true)
这意味着要修饰的方法需要返回引用类型实例或 null。
或者,您可以定义以下触发器:bool
Policy.HandleResult<bool>(_ => true)
这取决于你喜欢哪一个。这是一种解决方法,因为 Polly V7 不支持无条件触发。
评论