Skip to content

Commit

Permalink
Update/failure mode analysis (#239)
Browse files Browse the repository at this point in the history
* FailureModeAnalysis

* Remove unnecessary nuget packages

---------

Co-authored-by: Federico Arambarri <v-fearam>
Co-authored-by: Jason Bouska <[email protected]>
  • Loading branch information
v-fearam and skabou authored Nov 8, 2024
1 parent 2977c2b commit 03d1d62
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,38 @@
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;

namespace FailureModeAnalysisSample.Controllers
{
[ApiController]
[Route("[controller]")]
public class SampleController : ControllerBase
{
private readonly ILogger<SampleController> _logger;
private readonly IHttpClientFactory _httpClientFactory;
[ApiController]
[Route("[controller]")]
public class SampleController : ControllerBase
{
private readonly ILogger<SampleController> _logger;
private readonly IHttpClientFactory _httpClientFactory;

public SampleController(ILogger<SampleController> logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
public SampleController(ILogger<SampleController> logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}


[HttpGet]
public async Task<ActionResult> Get()
{
var httpClient = _httpClientFactory.CreateClient("SampleService");
[HttpGet]
public async Task<ActionResult> Get()
{
var httpClient = _httpClientFactory.CreateClient("SampleService");

HttpResponseMessage httpResponseMessage = await httpClient.GetAsync("<your GET operation>");
var content = await httpResponseMessage.Content.ReadAsStringAsync();
HttpResponseMessage httpResponseMessage = await httpClient.GetAsync("<your GET operation>");
var content = await httpResponseMessage.Content.ReadAsStringAsync();

if (httpResponseMessage.IsSuccessStatusCode)
{
return Ok(content);
}
_logger.LogError(content);
return StatusCode((int)httpResponseMessage.StatusCode, content);
}
}
if (httpResponseMessage.IsSuccessStatusCode)
{
return Ok(content);
}

_logger.LogError(content);
return StatusCode((int)httpResponseMessage.StatusCode, content);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.1.3" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.1" />
<PackageReference Include="Polly" Version="7.2.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.6" />
<PackageReference Include="Polly" Version="8.4.0" />
</ItemGroup>


Expand Down
26 changes: 13 additions & 13 deletions Reliability/FailureModeAnalysisSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

namespace RetryPatternSample
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
146 changes: 73 additions & 73 deletions Reliability/FailureModeAnalysisSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,77 +11,77 @@

namespace RetryPatternSample
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

private ILogger<Startup> _logger;

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//429 - Throttling - retry twice, incrementing wait time in every retry.
var retryWhenThrottling = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(5, retryAttempt)));

//408 - Timeout, retry twice, with a 5 secs wait time
var retryWhenTimeout = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(5));

//503 or 5xx service unavailable - wait 10 secs and retry only once.
var retryWhenServiceUnavailable = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.ServiceUnavailable)
.WaitAndRetryAsync(1, retryAttempt => TimeSpan.FromSeconds(10));

//401 unauthorized - retry once and do some retry logic + logging
var retryWhenUnauthorized = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(1, (exception, retryCount) =>
{
this._logger.LogError($"Error occurred retry attempt: {retryCount}, Error details: {exception.Result.ToString()}");
//Do some logic here like:
//RenewAccessToken();
});

IAsyncPolicy<HttpResponseMessage> policyWrap = Policy.WrapAsync(retryWhenThrottling, retryWhenTimeout, retryWhenServiceUnavailable, retryWhenUnauthorized);

services.AddHttpClient("SampleService", client =>
{
client.BaseAddress = new Uri(@"<You endpoint's base address here>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandler(policyWrap);

services.AddControllers();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
this._logger = logger;

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

private ILogger<Startup> _logger;

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//429 - Throttling - retry twice, incrementing wait time in every retry.
var retryWhenThrottling = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(5, retryAttempt)));

//408 - Timeout, retry twice, with a 5 secs wait time
var retryWhenTimeout = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(5));

//503 or 5xx service unavailable - wait 10 secs and retry only once.
var retryWhenServiceUnavailable = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.ServiceUnavailable)
.WaitAndRetryAsync(1, retryAttempt => TimeSpan.FromSeconds(10));

//401 unauthorized - retry once and do some retry logic + logging
var retryWhenUnauthorized = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(1, (exception, retryCount) =>
{

this._logger.LogError($"Error occurred retry attempt: {retryCount}, Error details: {exception.Result.ToString()}");
//Do some logic here like:
//RenewAccessToken();
});

IAsyncPolicy<HttpResponseMessage> policyWrap = Policy.WrapAsync(retryWhenThrottling, retryWhenTimeout, retryWhenServiceUnavailable, retryWhenUnauthorized);

services.AddHttpClient("SampleService", client =>
{
client.BaseAddress = new Uri(@"<You endpoint's base address here>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandler(policyWrap);

services.AddControllers();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
this._logger = logger;

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

0 comments on commit 03d1d62

Please sign in to comment.