Red*_*ddy 5 c# policy retrypolicy polly
我正在尝试将我现有的函数转换为 Polly Retry 策略
public static T Execute<T>(Func<T> getTask) where T : Task
{
var retryCount = 3;
while (retryCount-- > 0)
{
try
{
getTask().Wait();
return getTask();
} catch(Exception ex){
// handle retry
}
}
}
Run Code Online (Sandbox Code Playgroud)
转换成这个
public static T Execute<T>(Func<T> func) where T : Task
{
var task = func();
Policy.Handle<HttpRequestException>()
.Or<TimeoutException>()
.WaitAndRetryAsync(
3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(5, retryAttempt)),
(exception, timeSpan, retryCount, context) =>
{
//do some logging
})
.ExecuteAsync(func).Wait();
return task;
}
Run Code Online (Sandbox Code Playgroud)
和测试代码是
var retryCount = 0;
var res = HttpRetryWrapper.Execute(() => Task.Factory.StartNew<string>(function: () =>
{
if (++retryCount == 3)
{
return "fake";
}
throw new TimeoutException();
}));
Run Code Online (Sandbox Code Playgroud)
当我断言该res值时,我没有得到正确的结果。调试将我追踪到Execution没有正确等待结果的地方。
调用的次数test function是正确的。但是日志记录混乱,最终结果没有结果fake
对于通过硬编码 Polly 策略进行异步执行的辅助方法,其中执行TResult通过 a异步返回 type Task<TResult>,您可以采用:
public static Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> func)
{
return Policy.Handle<HttpRequestException>()
.Or<TimeoutException>()
.WaitAndRetryAsync(
3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(5, retryAttempt)),
(exception, timeSpan, retryCount, context) =>
{
//do some logging
})
.ExecuteAsync<TResult>(func); // This is an async-await-eliding contraction of: .ExecuteAsync<TResult>(async () => await func());
}
Run Code Online (Sandbox Code Playgroud)
(鉴于每次使用的策略都是相同的,您也可以考虑将策略存储在静态字段中并仅创建一次。)
注意:这(故意)不符合您对原始问题的评论中所述的合同,因为它牢不可破:
public static T Execute<T>(Func<T> func) where T : Task
Run Code Online (Sandbox Code Playgroud)
该子句最初看起来对旨在与or一起使用的where T : Taskor async 类异步方法很有吸引力。Jon Skeet在这里和这里解释了为什么它不适用于异步。您建议的辅助方法签名本身并不是异步的:TaskTask<T>
public static T Execute<T>(Func<T> func) where T : Task
Run Code Online (Sandbox Code Playgroud)
但是,.ExecuteAsync(async () => await func());在示例代码中引入会产生类似的问题。Polly.ExecuteAsync(...)重载正是为了与async/很好地配合await,以两种主要形式存在:
(1)Task ExecuteAsync(Func<Task> func)
(2)Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> func)
编译器必须在编译时选择其中之一:它不能(在您的示例代码中)在运行时将其编译为(1) 或 (2) 。因为它只知道T : Task它选择 (1),它返回Task。因此,您在对 @JamesFaix's 答案的评论中看到的错误:Cannot implicitly convert type Task to T。
如果您想要这种形式的帮助程序模式(调用者可以将其用于Task或Task<TResult>返回调用),则必须声明两者:
class HttpRetryWrapper
{
private static policy = Policy.Handle<HttpRequestException>()
.Or<TimeoutException>()
.WaitAndRetryAsync(
3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(5, retryAttempt)),
(exception, timeSpan, retryCount, context) =>
{
//do some logging
});
public static Task ExecuteAsync(Func<Task> func)
{
return policy.ExecuteAsync(func);
}
public static Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> func)
{
return policy.ExecuteAsync<TResult>(func);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,如果这是为了包装通过 发出的呼叫HttpClient,建议的模式是将 Polly 策略放置在 a 中DelegatingHandler,如@MuhammedRehanSaeed 的回答中所述。ASP.NET Core 2.1 支持使用 IHttpClientFactory创建此类的简洁DelegatingHandler声明。
| 归档时间: |
|
| 查看次数: |
7160 次 |
| 最近记录: |