首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Polly包重试时发生NullReferenceException错误

使用Polly包重试时发生NullReferenceException错误
EN

Stack Overflow用户
提问于 2022-08-30 16:24:49
回答 1查看 226关注 0票数 1

我们有.net 6服务,我们使用polly包(Polly,Version=7.0.0.0)重试瞬态api调用。我们看到System.NullReferenceException: Object没有设置为一个对象错误的实例。尽管重试似乎有效,但我认为代码中遗漏了一些东西。

我们能够看到用于重试的日志:

代码语言:javascript
复制
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调用或所有这些调用中。

代码语言:javascript
复制
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);
}

我们正在接收的错误如下:

代码语言:javascript
复制
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)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-31 11:41:42

正如Stephen Cleary在他的评论中提到的:在每次重试中构建一个全新的服务提供商是非常奇怪的。这不仅是奇怪的,而且根本没有必要。

提供对AddPolicyHandler has an overload的访问的IServiceProvider

代码语言:javascript
复制
services.AddHttpClient<IApiService, ApiService>()
        .AddPolicyHandler((provider, _) => GetPollyRetryPolicy(provider))

有了这一技术,您只需在ILogger委托中请求这样的onRetryAsync

代码语言:javascript
复制
var logger = provider.GetRequiredService<ILogger>();

我还建议使用静态Wrap方法而不是实例方法:

代码语言:javascript
复制
Policy.WrapAsync(Policy.TimeoutAsync(60), asyncPolicy);

Here I have detailed the differences between the alternatives

还请注意,订购事项:

  • 超时值外部,重试内部:
    • 超时操作为全局的、超疼痛的
    • 外部,超时为本地约束,因此它为每次重试尝试

    重新设置自身。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73545656

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档