Increased circuit breaker threshold

Fix lifescope issue with IHttpClient
Adapt circuit breaker to trigger its counter for no success http response
This commit is contained in:
Ramón Tomás 2017-03-22 12:24:55 +01:00
parent feafb4ba51
commit 6f8512f434
3 changed files with 22 additions and 20 deletions

View File

@ -8,6 +8,12 @@ using System.Threading.Tasks;
namespace WebMVC.Services.Utilities namespace WebMVC.Services.Utilities
{ {
/// <summary>
/// HttpClient wrapper that integrates Retry and Circuit
/// breaker policies when calling to Api services.
/// Currently is ONLY implemented for the ASP MVC
/// and Xamarin App
/// </summary>
public class HttpApiClientWrapper : IHttpClient public class HttpApiClientWrapper : IHttpClient
{ {
private HttpClient _client; private HttpClient _client;
@ -49,11 +55,11 @@ namespace WebMVC.Services.Utilities
Policy.Handle<HttpRequestException>() Policy.Handle<HttpRequestException>()
.WaitAndRetryAsync( .WaitAndRetryAsync(
// number of retries // number of retries
3, 3,
// exponential backofff // exponential backofff
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
// on retry // on retry
(exception, timeSpan, retryCount, context) => (exception, timeSpan, retryCount, context) =>
{ {
_logger.LogTrace($"Retry {retryCount} " + _logger.LogTrace($"Retry {retryCount} " +
$"of {context.PolicyKey} " + $"of {context.PolicyKey} " +
@ -62,27 +68,21 @@ namespace WebMVC.Services.Utilities
} }
); );
// Notice that these (and other methods below) are Task
// returning asynchronous methods. But, they do not
// have the 'async' modifier, and do not contain
// any 'await statements. In each of these methods,
// the only asynchronous call is the last (or only)
// statement of the method. In those instances,
// a Task returning method that does not use the
// async modifier is preferred. The compiler generates
// synchronous code for this method, but returns the
// task from the underlying asynchronous method. The
// generated code does not contain the state machine
// generated for asynchronous methods.
public Task<string> GetStringAsync(string uri) => public Task<string> GetStringAsync(string uri) =>
HttpInvoker(() => _client.GetStringAsync(uri)); HttpInvoker(() =>
_client.GetStringAsync(uri));
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item) => public Task<HttpResponseMessage> PostAsync<T>(string uri, T item) =>
// a new StringContent must be created for each retry // a new StringContent must be created for each retry
// as it is disposed after each call // as it is disposed after each call
HttpInvoker(() =>_client.PostAsync(uri, HttpInvoker(() =>
new StringContent(JsonConvert.SerializeObject(item), {
System.Text.Encoding.UTF8, "application/json"))); var response = _client.PostAsync(uri, new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"));
// raise exception if not success response
// needed for circuit breaker to track fails
response.Result.EnsureSuccessStatusCode();
return response;
});
public Task<HttpResponseMessage> DeleteAsync(string uri) => public Task<HttpResponseMessage> DeleteAsync(string uri) =>
HttpInvoker(() => _client.DeleteAsync(uri)); HttpInvoker(() => _client.DeleteAsync(uri));

View File

@ -54,11 +54,11 @@ namespace Microsoft.eShopOnContainers.WebMVC
if(Configuration.GetValue<string>("ActivateCircuitBreaker") == bool.TrueString) if(Configuration.GetValue<string>("ActivateCircuitBreaker") == bool.TrueString)
{ {
services.AddSingleton<IHttpClient, HttpApiClientWrapper>(); services.AddTransient<IHttpClient, HttpApiClientWrapper>();
} }
else else
{ {
services.AddSingleton<IHttpClient, HttpApiClient>(); services.AddTransient<IHttpClient, HttpApiClient>();
} }
} }

View File

@ -11,6 +11,8 @@ import 'rxjs/add/operator/catch';
import { SecurityService } from './security.service'; import { SecurityService } from './security.service';
import { Guid } from '../../../guid'; import { Guid } from '../../../guid';
// Implementing a Retry-Circuit breaker policy
// is pending to do for the SPA app
@Injectable() @Injectable()
export class DataService { export class DataService {
constructor(private http: Http, private securityService: SecurityService) { } constructor(private http: Http, private securityService: SecurityService) { }