Polly Circuit Breaker excepciones manejadas y no manejadas

Nov 24 2020

Quiero usar Polly para implementar un patrón de disyuntor.

En los documentos, hay una descripción del estado Half Open , y allí dice:

  • Si se recibe una excepción manejada, esa excepción se vuelve a lanzar, y el circuito vuelve a abrirse inmediatamente y permanece abierto nuevamente durante el período de tiempo configurado.
  • Si se recibe una excepción no controlada, el circuito permanece semiabierto.

No estoy seguro de entender la diferencia aquí entre excepción manejada y no manejada. Estamos describiendo un caso en el que la política ejecuta una acción y genera una excepción.

Cuando dicen que se maneja la excepción, ¿dónde quieren decir que se maneja? porque, como dijimos, la acción lo arrojó, ¿no significa que no está controlado?

Me hace no entender completamente cuándo el estado medio abierto permanece medio abierto y cuándo pasa a estar abierto.

Respuestas

1 PeterCsala Nov 25 2020 at 09:20

Cuando define una política de disyuntor, puede definir qué tipo de excepciones deben ser consideradas por la implementación de CB . En otras palabras, puede enumerar aquellas excepciones que deberían tratarse como ejecución fallida y deberían contarse en el recuento de fallos sucesivos.

Puede definir la lista de excepciones con la combinación de Handle<T>y Or<T>llamadas a métodos.

Examinemos este concepto a través de un ejemplo simple:

var retry = Policy
    .Handle<ArgumentException>()
    .Or<NotSupportedException>()
    .WaitAndRetry(5, _ => TimeSpan.FromSeconds(1),
        onRetry: (exception, delay, context) => Console.WriteLine($"{"Retry",-10}{delay,-10:ss\\.fff}: {exception.GetType().Name}")); var circuitBreaker = Policy .Handle<ArgumentException>() .CircuitBreaker(2, TimeSpan.FromSeconds(1), onBreak: (ex, @break) => Console.WriteLine($"{"Break",-10}{@break,-10:ss\\.fff}: {ex.GetType().Name}"),
        onReset: () => Console.WriteLine($"{"Reset",-10}"), onHalfOpen: () => Console.WriteLine($"{"HalfOpen",-10}"));
  • La política de disyuntores considera todos ArgumentExceptionlos correos electrónicos (incluidos ArgumentNullExceptiony ArgumentOutOfRangeException) como excepción manejada.
    • Esto significa que si el delegado llamado lanza una de estas tres excepciones, aumentará el recuento de fallas sucesivas y, si se alcanza el umbral, se romperá.
  • La política de reintento se activa en caso de ArgumentExceptiony también en caso de NotSupportedException.
    • Si se lanza cualquiera de estos, se suspenderá por un segundo y luego intentará volver a ejecutar el mismo delegado.

Entonces, desde la perspectiva del disyuntor, si NotSupportedExceptionse lanza un, no se considerará >> de ahí el nombre no manejado.

Así es como se implementa nuestro método de muestra que arrojará un ArgumentExceptiono un NotSupportedException:

private static int count = 0;
private const int threshold = 3;
static void SampleCall()
{
    count++;
    if (count >= threshold) throw new NotSupportedException();
    throw new ArgumentException("Nothing");
}

El uso de las políticas:

var strategy = Policy.Wrap(retry, circuitBreaker);

try
{
    strategy.Execute(SampleCall);
    Console.WriteLine("Succeeded");
}
catch (NotSupportedException)
{
    Console.WriteLine("Failed");
}

Salida cuando thresholdse establece en 3

Retry     01.000    : ArgumentException
Break     01.000    : ArgumentException
Retry     01.000    : ArgumentException
HalfOpen
Retry     01.000    : NotSupportedException
Retry     01.000    : NotSupportedException
Retry     01.000    : NotSupportedException
Failed

Una vez que el CB se ha transferido al HalfOpenestado, los SampleCalllanzamientos solo son NotSupportedExceptions. Esto no lo maneja el CB, por eso permanece en el HalfOpenestado.

Salida cuando thresholdse establece en 2

Retry     01.000    : ArgumentException
Retry     01.000    : NotSupportedException
Retry     01.000    : NotSupportedException
Retry     01.000    : NotSupportedException
Retry     01.000    : NotSupportedException
Failed

El CB no se rompió porque no hubo dos sucesivos ArgumentException. Pero el reintento se activó porque también maneja NotSupportedException.

Salida cuando thresholdse establece en 4

Retry     01.000    : ArgumentException
Break     01.000    : ArgumentException
Retry     01.000    : ArgumentException
HalfOpen
Break     01.000    : ArgumentException
Retry     01.000    : ArgumentException
HalfOpen
Retry     01.000    : NotSupportedException
Retry     01.000    : NotSupportedException
Failed

Debido a SampleCallque lanzó ArgumentExceptioncuando el CB estaba en el HalfOpenestado, es por eso que CB consideró eso como una excepción manejada y se transfirió de HalfOpena Open.