Fork me on GitHub
Show / Hide Table of Contents

Objective

ComposableAsync.Resilient provides dispatchers that implement resilient behaviors to handle exceptions.

Features

CircuitBreakerPolicy

Circuit breaker pattern allows to stop stressing a service under failure.

  • Circuit breaker starts with state open:
    • calls to circuit breaker calls the service
    • the number of successive exceptions raised is counted
  • When this number reaches a threshold, state switches to open:
    • call to original service are stopped
    • circuit breaker emits whether exception or returns a default value
  • When open, after a time-out circuit breaker enters in half-open mode:
    • service is called again
      • in case of success the state switches to closed state
      • in case of failure the state switches to open

Create a CircuitBreaker for all exceptions:

// Create a circuit breaker that opens after 5 consecutive exceptions and stays open 500ms before re-trying
var circuitBreaker = CircuitBreakerPolicy.ForAllException().WithRetryAndTimeout(5, TimeSpan.FromMilliseconds(500));

// Use this dispatcher for executing method DoExecute
await circuitBreaker.Enqueue(() => DoExecute());

For specific exceptions:

// Create a circuit breaker for all that opens after 10 consecutive TimeoutException and stays open 500ms before re-trying
var circuitBreaker = CircuitBreakerPolicy.For<TimeoutException>().WithRetryAndTimeout(10, TimeSpan.FromMilliseconds(500));
// Create circuit breaker for exception that opens after 5 consecutive exceptions with the expected message and stays open 500ms before re-trying
var circuitBreaker = CircuitBreakerPolicy.ForException(ex => ex.Message == expected).WithRetryAndTimeout(5, TimeSpan.FromMilliseconds(500));
// Create circuit breaker that opens after 15 consecutive SystemException and stays open 5s before re-trying
var circuitBreaker = CircuitBreakerPolicy.For<SystemException>(ex => ex.Message == expected).WithRetryAndTimeout(15, TimeSpan.FromSeconds(5));

Return default or specific values

By default the circuit-breaker will throw an CircuitBreakerOpenException when opened.

It is possible to configure a circuit-breaker to implement alternative logic when opened:

// Create circuit breaker that opens after 15 consecutive SystemException and stays open 5s before re-trying
var circuitBreaker = CircuitBreakerPolicyForAllException().ReturnsDefaultWhenOpen().WithRetryAndTimeout(15, TimeSpan.FromSeconds(5));

// When opened the res value will be 0
var res = await circuitBreaker.Enqueue(() => GetIntValue());
// Create circuit breaker that opens after 15 consecutive SystemException and stays open 5s before re-trying
var circuitBreaker = CircuitBreakerPolicyForAllException().ReturnsWhenOpen<string>("open circuit").WithRetryAndTimeout(15, TimeSpan.FromSeconds(5));

// When opened the res value will be "open circuit"
var res = await circuitBreaker.Enqueue(() => GetStringValue());

Prevent exception for function returning void or Task

// Create circuit breaker that opens after 15 consecutive SystemException and stays open 5s before re-trying
var circuitBreaker = CircuitBreakerPolicyForAllException().DoNotThrowForVoid().WithRetryAndTimeout(15, TimeSpan.FromSeconds(5));

// This will not throw when circuit opens
await circuitBreaker.Enqueue(() => ExecuteCommand());

RetryPolicy

RetryPolicy provide a dispatcher factory that will re-execute a statement in case that its previous execution raise an exception.

For all exceptions:

// Create dispatcher that catch all exceptions and retry for ever
var forEverDispatcher = RetryPolicy.ForAllException().ForEver();

// Use this dispatcher for executing method DoExecute
await forEverDispatcher.Enqueue(() => DoExecute());
// Create dispatcher that catch all exceptions and retry up to 5 times, after that the original exception is re-thrown.
var forEverDispatcher = RetryPolicy.ForAllException().WithMaxRetry(5);

For exception by type:

// Create dispatcher that catch all ArgumentException and retry for ever
var forArgumentExceptionDispatcher = RetryPolicy.For<ArgumentException>().ForEver();
// Create dispatcher that catch all ArgumentException and NullReferenceException and retry execute action for ever
var selectiveDispatcher = RetryPolicy.For<ArgumentException>().And<NullReferenceException>().ForEver();

With wait between retries:

// Create dispatcher that catch all ArgumentException and retry for ever with a delay of 200 ms
var forArgumentExceptionDispatcher = RetryPolicy.For<ArgumentException>().WithWaitBetweenRetry(200).ForEver();
// alternatively
var forArgumentExceptionDispatcher = RetryPolicy.For<ArgumentException>().WithWaitBetweenRetry(TimeSpan.FromSeconds(0.2)).ForEver();

With variable waits between retries:

// Create dispatcher that catch all ArgumentException exception and retry up to three times with a delay of 10ms between first and second try, then 50ms between second and third, then 200ms between third and fourth.
var forArgumentExceptionDispatcher = RetryPolicy.For<ArgumentException>().WithWaitBetweenRetry(10,50,200).WithMaxRetry(3);

Using a function to compute waits between retries:

// Create dispatcher that catch all ArgumentException exception and retry up to three times with an variable delay of 100ms * number of retry between try.
var forArgumentExceptionDispatcher = RetryPolicy.For<ArgumentException>().WithWaitBetweenRetry(retry => TimeSpan.FromMilliseconds(retry * 100)).WithMaxRetry(3);

Match a specific exception:

// Create dispatcher that catch all Exception with a specific message for ever.
var forArgumentExceptionDispatcher = RetryPolicy.ForException(ex => ex.Message == expectedMessageString).ForEver();
// Create dispatcher that catch all ArgumentException with a specific message for ever.
var forArgumentExceptionDispatcher = RetryPolicy.For<ArgumentException>(ex => ex.Message == expectedMessageString).ForEver();

As any dispatcher, ComposableAsync.Resilient dispatchers can also be transformed into httpHandler or used ro proxify POCO thanks to ComposableAsync.Resilient and ComposableAsync.Resilient respectively.

Nuget

Install-Package ComposableAsync.Resilient

Go nuget packages

  • Improve this Doc
Back to top Generated by DocFX