Реагирование на 429 исключений (регулирование) с использованием Castle.Windsor и Polly - PullRequest
0 голосов
/ 01 ноября 2019

Мы боремся с 429 HTTP-исключениями (исходящими от SharePoint в Интернете или Microsoft Graph), и я хочу использовать Polly и Castle.Windsor для этого.

Мой код (в выдержках)

Регистрация вещей Полли в моем контейнере Castle.Windsor:

_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?

...