我们有.net 6服务,我们使用polly包(Polly,Version=7.0.0.0)重试瞬态api调用。我们看到System.NullReferenceException: Object没有设置为一个对象错误的实例。尽管重试似乎有效,但我认为代码中遗漏了一些东西。
我们能够看到用于重试的日志:
NotExtended delaying for 1000 ms, then making retry 1 {...data..}
NotExtended delaying for 1000 ms, then making retry 2 {...data..}
NotExtended delaying for 1000 ms, then making retry 3 {...data..}因为我对Polly的工作方式很陌生,所以不知道我们在下面的代码中到底遗漏了什么。任何建议都会很有帮助。提前谢谢。
P.S.:我在粘贴代码片段,在这里我们使用polly包,而不是与polly实现无关的代码行,以避免混淆。
不确定此错误是否发生在很少的api调用或所有这些调用中。
using Polly;
using Polly.Extensions.Http;
using Polly.Wrap;
services.AddHttpClient<IApiService, ApiService>()
.AddPolicyHandler(GetPollyRetryPolicy(builder.services));
private static AsyncPolicyWrap<HttpResponseMessage> GetPollyRetryPolicy(IServiceCollection services)
{
var asyncPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
onRetryAsync: async (outcome, timespan, retryAttempt, context) =>
{
var serviceProvider = services.BuildServiceProvider();
var data = new
{
url = outcome.Result?.RequestMessage?.RequestUri?.ToString(),
method = outcome.Result?.RequestMessage?.Method?.Method,
resultContent = await outcome.Result?.Content?.ReadAsStringAsync()
};
serviceProvider.GetService<ILogger>()
?.Warn($"{outcome.Result.StatusCode} delaying for {timespan.TotalMilliseconds} ms, " +
$"then making retry {retryAttempt}", data: data, ex: outcome.Exception);
});
return Policy.TimeoutAsync(60).WrapAsync(asyncPolicy);
}我们正在接收的错误如下:
System.NullReferenceException: Object reference not set to an instance of an object.
--- End of stack trace from previous location ---
at Polly.Retry.AsyncRetryEngine.ImplementationAsync[TResult](Func`3 action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldRetryExceptionPredicates, ResultPredicates`1 shouldRetryResultPredicates, Func`5 onRetryAsync, Int32 permittedRetryCount, IEnumerable`1 sleepDurationsEnumerable, Func`4 sleepDurationProvider, Boolean continueOnCapturedContext)
at Polly.AsyncPolicy`1.ExecuteAsync(Func`3 action, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext)
at Polly.Wrap.AsyncPolicyWrapEngine.<>c__DisplayClass2_0`1.<<ImplementationAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Polly.Timeout.AsyncTimeoutEngine.ImplementationAsync[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Func`2 timeoutProvider, TimeoutStrategy timeoutStrategy, Func`5 onTimeoutAsync, Boolean continueOnCapturedContext)
at Polly.Timeout.AsyncTimeoutEngine.ImplementationAsync[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Func`2 timeoutProvider, TimeoutStrategy timeoutStrategy, Func`5 onTimeoutAsync, Boolean continueOnCapturedContext)
at Polly.AsyncPolicy.ExecuteAsync[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext)
at Polly.Wrap.AsyncPolicyWrapEngine.ImplementationAsync[TResult](Func`3 func, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext, IAsyncPolicy outerPolicy, IAsyncPolicy`1 innerPolicy)
at Polly.AsyncPolicy`1.ExecuteAsync(Func`3 action, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext)
at Microsoft.Extensions.Http.PolicyHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)发布于 2022-08-31 11:41:42
正如Stephen Cleary在他的评论中提到的:在每次重试中构建一个全新的服务提供商是非常奇怪的。这不仅是奇怪的,而且根本没有必要。
提供对AddPolicyHandler has an overload的访问的IServiceProvider
services.AddHttpClient<IApiService, ApiService>()
.AddPolicyHandler((provider, _) => GetPollyRetryPolicy(provider))有了这一技术,您只需在ILogger委托中请求这样的onRetryAsync:
var logger = provider.GetRequiredService<ILogger>();我还建议使用静态Wrap方法而不是实例方法:
Policy.WrapAsync(Policy.TimeoutAsync(60), asyncPolicy);Here I have detailed the differences between the alternatives。
还请注意,订购事项:
重新设置自身。
https://stackoverflow.com/questions/73545656
复制相似问题