[英]Polly policy to log exception and rethrow
我考虑使用Polly创建策略来记录异常并重新抛出。 我没有找到允许开箱即用的现有方法,但我看到的一些选项是
倒退
// Specify a substitute value or func, calling an action (e.g. for logging)
// if the fallback is invoked.
Policy.Handle<Whatever>()
.Fallback<UserAvatar>(UserAvatar.Blank,
onFallback: (exception, context) =>
{
_logger.Log(exception, context);
throw exception;
});
问题:可以从 Fallback 中抛出异常吗?
暂停
Policy.Timeout(1, T30meoutStrategy.Pessimistic,
(context, timespan, task) =>
{
// ContinueWith important!: the abandoned task may very well still be executing,
// when the caller times out on waiting for it!
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
logger.Error(context,t.Exception);
throw exception;
}
});
}
或重试
Policy.Handle<DivideByZeroException>().Retry(0,
(exception, retryCount) =>
{
logger.Error(context,exception);
throw exception;
});
问题:是否支持0次重试?
或者 KISS 并自己编写简单的 try/catch with throw。
这些方法哪种更好? 你有什么建议?
如果您还没有 Polly,那么 try/catch 似乎是最简单的。
如果您已经有 Polly,则可以按照您建议的方式安全地重新调整FallbackPolicy
的用途。 onFallback
委托和回退操作或值不受.Handle<>()
子句控制,因此您可以安全地从onFallback
委托中重新抛出异常。
Policy<UserAvatar>.Handle<Whatever>()
.Fallback<UserAvatar>(UserAvatar.Blank,
onFallback: (exception, context) =>
{
_logger.Log(exception, context);
throw exception;
});
您的问题使用TimeoutPolicy
概述的方法只会捕获调用者先前因超时而离开的委托引发的异常,并且仅在TimeoutMode.Pessimistic
; 并非所有例外。
您的问题概述的方法.Retry(0, ...)
不起作用。 如果未指定重试,则不会调用onRetry
委托。
为了避免重新利用FallbackPolicy
的不整洁,您还可以在 Polly 的结构中编写自己的LogThenRethrowPolicy
。 此提交(添加了简单的NoOpPolicy
)举例说明了添加新策略所需的最低限度。 您可以添加类似于NoOpPolicy
的实现,但只需try { } catch { /* log; rethrow */ }
try { } catch { /* log; rethrow */ }
编辑 2019 年 1 月:Polly.Contrib 现在还包含一个Polly.Contrib.LoggingPolicy可以帮助解决这个问题。
https://github.com/App-vNext/Polly-Samples/blob/master/PollyDemos/Async/AsyncDemo02_WaitAndRetryNTimes.cs显示您可以使用onRetry:
选项,至少对于 WaitAndRetryAsync。 其他的我还没看。
HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) // exponential back-off: 2, 4, 8 etc
+ TimeSpan.FromMilliseconds(Jitterer.Next(0, 1000)), // plus some jitter: up to 1 second
onRetry: (response, calculatedWaitDuration) =>
{
logger.LogError($"Failed attempt. Waited for {calculatedWaitDuration}. Retrying. {response.Exception.Message} - {response.Exception.StackTrace}");
}
);
这是我的通用方法解决方案
public async Task<T> PollyRetry<T>(
Func<Task<T>> action)
{
bool hasFallback = false;
Exception ex = null;
var fallbackPolicy = Policy<T>.Handle<Exception>().FallbackAsync(
default(T), d =>
{
//log final exception
ex = d.Exception;
hasFallback = true;
return Task.FromResult(new { });
});
var retryPolicy = Policy
.Handle<Exception>()
.WaitAndRetryAsync(3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(res, timeSpan, context) =>
{
//log exception
});
var policyResult = await fallbackPolicy.WrapAsync(retryPolicy).ExecuteAndCaptureAsync(action);
if (hasFallback && ex != null)
throw ex;
return policyResult.Result;
}
//call service with retry logic
TestResponse response = await _pollyRetryService.PollyRetry(async () =>
{
return await _testService.Test(input);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.