Thursday, 23 November 2017

Fault Handling in Xamarin.Forms: Circuit Breaker using Polly

Previously I wrote about about handling faults that take a variable amount of time to recover from, in Xamarin.Forms, and discussed an implementation of the circuit breaker pattern. The advantage of the implementation was that the circuit breaker pattern was implemented without requiring any library code, for those sensitive to bloating their application package size.

There are, however, fault handling libraries available and the go to library for .NET is Polly, which includes fluent support for the circuit breaker pattern, and much more. In Polly, the various patterns are implemented via fault handling policies, which handle specific exceptions thrown by, or results returned by, the delegates that are executed through the policy.

This blog post will discuss using Polly’s CircuitBreakerPolicy, which implements the circuit breaker pattern.

Implementation

The sample application, which can be found on GitHub, is similar to the sample application from my previous blog post, with the custom implementation of the circuit breaker pattern replaced with Polly’s.

Initialization

The App class in the sample application initializes the classes that are responsible for communicating with the REST service:

TodoManager = new TodoItemManager( new RestService( new ResilientRequestProvider()));

The RestService class provides data to the TodoItemManager class, with the RestService class making REST calls using the ResilientRequestProvider class, which uses Polly to implement the circuit breaker pattern.

ResilientRequestProvider

The following code example shows the GetAsync method from the ResilientRequestProvider class, which makes GET requests to a specified URI:

async Task<HttpResponseMessage> HttpInvoker(Func<Task<HttpResponseMessage>> operation) { return await circuitBreakerPolicy.ExecuteAsync(operation); } public async Task<TResult> GetAsync<TResult>(string uri) { string serialized = null; var httpResponse = await HttpInvoker(async () => { var response = await client.GetAsync(uri); response.EnsureSuccessStatusCode(); serialized = await response.Content.ReadAsStringAsync(); return response; }); return JsonConvert.DeserializeObject<TResult>(serialized); }

The GetAsync method code is identical to my previous blog post. The lambda expression is passed to the HttpInvoker method, which in turn passes it to the ExecuteAsync method of the CircuitBreakerPolicy instance. Therefore, the code in the lambda expression is what will be executed by the circuit breaker, provided it’s in a state that allows that.

There are three steps to using a fault handling policy, including the CircuitBreakerPolicy, in Polly:

  1. Specify the exceptions you want the policy to handle.
  2. Optionally specify the returned results you want the policy to handle.
  3. Specify how the policy should handle any faults.

The following code example shows the first and third steps, used in the sample application, for defining the operation of the CircuitBreakerPolicy instance:

circuitBreakerPolicy = Policy .Handle<Exception>() .CircuitBreakerAsync( 1, TimeSpan.FromSeconds(5), // onBreak (exception, delay) => Debug.WriteLine($"Breaking the circuit for {delay.TotalSeconds} due to {exception.Message}"), // onReset () => Debug.WriteLine($"Call ok - closing the circuit again."), // onHalfOpen () => Debug.WriteLine($"Circuit is half-open. The next call is a trial."));

The Policy.Handle method is used to specify the exceptions you want the policy to handle. In this example the circuit breaker will trigger after a specified number of consecutive exceptions of the handled type (Exception).

After specifying the exceptions the policy should handle, you must specify how the policy should handle any faults with the CircuitBreakerAsync method. There are multiple overloads for this method, and I used one for which five arguments must be specified:

  1. The consecutive number of exceptions that must be thrown to break the circuit. This is set to 1 in the sample application, purely for demonstration purposes.
  2. The duration to keep the circuit broken for. This is set to 5s in the sample application, purely for demonstration purposes.
  3. An action to be called when the circuit changes to an Open state.
  4. An action to be called when the circuit changes to a Closed state.
  5. An action to be called when the circuit changes to a Half-open state.

Executing a Delegate through the Policy

The overall operation is that the GetAsync method in the ResilientRequestProvider class invokes the HttpInvoker method, passing a Func that represents the GET request. The HttpInvoker method invokes Polly’s CircuitBreakerPolicy.ExecuteAsync method, passing the received Func as an argument.

The circuit breaker policy then attempts to execute the Func passed in via the ExecuteAsync method. The circuit initially starts closed and executes the Func, and measures its fault or success. If the number of consecutive faults exceeds a specified threshold (1), the circuit will break (move to an Open state).

When the circuit is in an Open state, any attempts to execute code through the policy will fail with a BrokenCircuitException being thrown. The circuit remains in an Open state for the duration specified by the CircuitBreakerAsync method (5s). After that timespan the circuit transitions to a Half-open state.

When the circuit is in a Half-open state, the delegate passed to the ExecuteAsync method will be attempted. If it succeeds the circuit transitions back to a Closed state. However, if the delegate throws a handled exception, the circuit transitions back to the Open state, remaining open for the configured timespan.

Summary

Polly is a .NET fault handling library, which includes fluent support for the circuit breaker pattern. In Polly, the circuit breaker pattern is implemented by the CircuitBreakerPolicy type, which handles specific exceptions thrown by, or results returned by, the delegates that are executed through the policy.

The CircuitBreakerPolicy type is highly configurable, allowing you to specify the exceptions to be handled, the returned results to be handled (not covered here), and how the policy should handle any faults.

The advantage of using Polly over implementing your own circuit breaker pattern is that Polly includes multiple fault handling patterns that can easily be combined for additional resilience when handling faults.

No comments:

Post a Comment