Политика Polly для регистрации исключений и повторного выброса

Я полагаю, чтобы использовать Полли, чтобы создать политику, чтобы регистрировать исключения и перебрасывать. Я не нашел существующего метода, который бы позволял это из коробки, но некоторые варианты, которые я вижу, являются

Отступать

// Specify a substitute value or func, calling an action (eg 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) =>  
   {        task.ContinueWith(t =>
 { // ContinueWith important!: the abandoned task may very well still be executing, when the caller times out on waiting for it!    
   if (t.IsFaulted      )           
  {             
       logger.Error(context,t.Exception);         
       throw exception;
  }   );    

Или повторите

Policy.Handle<DivideByZeroException>().Retry(0, (exception, retryCount) =>   
  {                logger.Error(context,exception);         
throw exception;
  }   );  

Вопрос: поддерживается ли 0 попыток?

Или ПОЦЕЛУЙ и напиши простой try/catch с throw сам.

Какой из этих методов лучше? Каковы ваши рекомендации?

3 ответа

Решение

Если у вас еще нет Полли, попробуйте / поймать.

Если у вас уже есть Полли в смеси, 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 Вы также можете написать свой собственный LogThenRethrowPolicy в структурах Полли. Этот коммит (который добавил простое NoOpPolicy) иллюстрирует минимум, необходимый для добавления новой политики. Вы можете добавить реализацию, аналогичную NoOpPolicy но просто try { } catch { /* log; rethrow */ }

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);

        });
Другие вопросы по тегам