Polly Circuit Breaker / Retry для автоматического перезапуска запросов после отключения сети - PullRequest
0 голосов
/ 09 ноября 2018

Я реализую шаблоны прерывателя и повторных попыток через Polly в .NET Framework 4.5.2.

Я хочу посмотреть, правильно ли мое понимание.

Вопрос 1. Если произошел сбой в сети, и автоматический выключатель достиг номера ExceptionAllowedBeforeBreaking, перешел в открытое состояние и ждал период durationOfBreak, канал будет открыт для новых запросов, но те, которые были отправлены, будут выбрасывать исключение?

Вопрос 2: Если желаемое поведение относится к тем запросам, для которых были повторены исключения, а не к прерывателю, выдавшему исключение, то в дополнение к политике автоматического выключателя должна быть реализована политика повторных попыток. Насколько я понимаю, такое поведение будет иметь место в вопросе 1, а затем будет предпринята попытка повторения.

A. Если произошел сбой сети или служба не работает, и желаемое поведение заключается в повторной попытке запроса, как только сеть будет восстановлена ​​или служба снова будет работать, потребуется выполнить RetryForever. Есть ли лучший способ сделать это? Эффективно будет много блокировок, верно?

С точки зрения кода, мои политики в настоящее время определены как:

    const int maxRetryAttempts = 3;

    const int exceptionsAllowedBeforeBreaking = 2;
    const int pauseBetweenFailures = 2;
    readonly Policy retryPolicy = Policy
        .Handle<Exception>()
        .RetryAsync(maxRetryAttempts, (exception, retryCount) => System.Diagnostics.Debug.WriteLine($"Retry {retryCount}"));

    readonly Policy circuitBreakerPolicy = Policy
        .Handle<Exception>()
        .CircuitBreakerAsync(exceptionsAllowedBeforeBreaking: exceptionsAllowedBeforeBreaking,
                durationOfBreak: TimeSpan.FromSeconds(pauseBetweenFailures),
                onBreak: (e, span) => System.Diagnostics.Debug.WriteLine("Breaking circuit for " + span.TotalMilliseconds + "ms due to " + e.Message),
                onReset: () => System.Diagnostics.Debug.WriteLine("Trial call succeeded: circuit closing again."),
                onHalfOpen: () => System.Diagnostics.Debug.WriteLine("Circuit break time elapsed.  Circuit now half open: permitting a trial call."));

Мой код вызова сделан так:

var response = await retryPolicy.WrapAsync(circuitBreakerPolicy).ExecuteAsync(() => this.client.SendAsync<TData, JObject>(message, cancel, jsonSerializer));

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

1 Ответ

0 голосов
/ 10 ноября 2018

Вопрос 1: Если произошел сбой в сети, и автоматический выключатель достиг номера ExceptionAllowedBeforeBreaking, перешел в разомкнутое состояние и ждал период продолжительностиOfBreak, цепь будет открыта для новых запросов ...

После того, как durationOfBreak пройдет, схема перейдет в полуоткрытое состояние, в течение которого разрешен один пробный вызов (в текущей реализации) .

... но те, которые были отправлены, выдают исключение?

Вызовы, которые были размещены в состоянии Open, будут выбрасывать BrokenCircuitException.

Вопрос 2: Если желаемое поведение относится к тем запросам, для которых были повторены исключения, а не к прерывателю цепи, выдавшему исключение, то в дополнение к политике автоматического выключателя должна быть реализована политика повторных попыток. Насколько я понимаю, такое поведение будет иметь место в вопросе 1, а затем будет предпринята попытка повторения.

Правильно. Автоматический выключатель по-прежнему выбрасывает BrokenCircuitException (нет «вместо», который останавливает автоматический выключатель). Однако, если политика повторных попыток упаковки обрабатывает это исключение, BrokenCircuitException не будет передано обратно в вызывающий код. Работоспособные примеры можно найти в Polly-Samples или this dotnetfiddle .

A. Если произошел сбой сети или служба не работает, и желаемое поведение заключается в повторной попытке запроса, как только сеть будет восстановлена ​​или служба снова будет работать, потребуется выполнить RetryForever. Эффективно будет много блокировок, верно?

Политика Polly управляет только тем, что происходит на этом пути выполнения, не зная, существуют ли похожие параллельные выполнения. Так что да, если есть RetryForever, и если вы ожидаете, что большое число вызовов будет зацикливаться в этом RetryForever, в то время как связь теряется, существует риск увеличения объема памяти / ресурсов со многими операциями в образце удержания. Чтобы узнать, является ли это серьезной проблемой для вашего приложения / архитектуры, вам необходимо протестировать ее в представительной среде.

Есть ли лучший способ сделать это?

Вы можете ограничить количество повторных попыток и захват неудачных отправок в какую-то очередь. Когда подключение восстановлено, вы можете повторно отправить элементы из очереди сбоев.

...