[我们正在处理429个HTTP异常(来自SharePoint Online或Microsoft Graph),我想利用Polly和Castle.Windsor来解决这个问题。
我的代码是(摘录中的)
在我的Castle.Windsor容器中注册Polly的东西:
_container.Register(Component.For<IRepository>()
.ImplementedBy<Repository>()
.DependsOn(Dependency.OnValue<ImportSettings>(_importSettings))
.Interceptors(InterceptorReference.ForKey("throttle")).Anywhere
.LifestyleTransient());
_container.Register(Component.For<WaitAndRetryInterceptor<WebException>>().LifeStyle.Singleton
.Named("throttle"));
我的波莉的东西:
public class WaitAndRetryInterceptor<T> : IInterceptor where T : WebException
{
private readonly RetryPolicy _policy;
public void Intercept(IInvocation invocation)
{
var dictionary = new Dictionary<string, object> {{"methodName", invocation.Method.Name}};
_policy.Execute(invocation.Proceed, dictionary);
}
public WaitAndRetryInterceptor()
{
_policy =
Policy
.Handle<T>()
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(32), TimeSpan.FromSeconds(64),
TimeSpan.FromSeconds(128), TimeSpan.FromSeconds(256), TimeSpan.FromSeconds(512)
});
}
}
因此,此实现满足了我的需求-但非常保守。因此,我尝试实现对抛出429异常的直接支持-特别是对服务器上可用的Reply-After
标头的支持。
我从此https://github.com/App-vNext/Polly/issues/414中发现,我需要实现对支持sleepDurationProvider
的重载之一的支持,但是我在使我的代码正确时遇到问题。
我的实现是这样:
_policy =
Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Accepted) //needs to be changed to 429
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: (retryCount, response) =>
{
return getServerWaitDuration(response);
})
;
getServerWaitDuration
简单返回一个TimeSpan
private TimeSpan getServerWaitDuration(DelegateResult<HttpResponseMessage> response)
{
return TimeSpan.Zero; //not actual code ;-)
}
想法是,我将仅查看服务器响应的标头,并将时间跨度传递回sleepDurationProvider
。
但是-从配置sleepDurationProvider
的行中出现错误。有人告诉我(retryCount, response)
是“不兼容的匿名函数签名”
我觉得我这里缺少明显的东西。但为什么?我如何访问response
对象以提取Retry-After
持续时间?
您可能会像这样查看标题
public AsyncRetryPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
.OrResult(r => r?.Headers?.RetryAfter != null)
.WaitAndRetryAsync(
3,
sleepDurationProvider: (retryCount, response, context) =>
{
return response.Result.Headers.RetryAfter.Delta.Value;
},
onRetryAsync: (e, ts, i, ctx) => Task.CompletedTask
);
}