Background

When our applications need to communicate with many other services or components, we will meet temporary faults due to some of services or components that cannot respond in time.
There are many reasons for those temporary faults -- timeouts, overloaded resources, networking hiccups and so on. Most of them are hard to reproduce because these failures are usually self-correcting.
We can't avoid failures, but we can respond in ways that will keep our system up or at least minimize downtime.
For example, an application service with a throttling strategy is processing plenty of concurrent requests, and some of the requests will be rejected quickly. But if we can try again after a delay, it might succeed. Retry is an effective and easy way to handle transient failures.
And in this article, we will discuss it in ASP.NET Core via Polly.

What Is Polly?

Using Retry Pattern In ASP.NET Core Via Polly
Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.

How To Use?

In the section, I will share two common scenarios, one is HTTP(s) request, the other one is sending a message to the message bus.

HTTP(s) request

Retry pattern with HTTP(s) request is very easy, because of the combination of Polly and HttpClientFactory.
What we need to do is use an extension method named AddPolicyHandler to add the retry policy for the HttpClient.
Here is the sample code to configure.
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddHttpClient("csharpcorner")
  4. .SetHandlerLifetime(TimeSpan.FromMinutes(5))
  5. // important step
  6. .AddPolicyHandler(GetRetryPolicy())
  7. ;
  8. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  9. }
  10. private IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
  11. {
  12. return HttpPolicyExtensions
  13. // HttpRequestException, 5XX and 408
  14. .HandleTransientHttpError()
  15. // 404
  16. .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
  17. // Retry two times after delay
  18. .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
  19. ;
  20. }
GetRetryPolicy method means that when network failures or HTTP 5XX or 408 status codes will trigger retry mechanism.
To run the controller, we don't need to add some additional code before we send the HTTP(s) request, just keep the same behavior when we use HttpClient.
  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class ValuesController : ControllerBase
  4. {
  5. private readonly IHttpClientFactory _clientFactory;
  6. public ValuesController(IHttpClientFactory clientFactory)
  7. {
  8. _clientFactory = clientFactory;
  9. }
  10. // GET api/values
  11. [HttpGet]
  12. public async Task<string> GetAsync()
  13. {
  14. // define a 404 page
  15. var url = $"https://www.c-sharpcorner.com/mytestpagefor404";
  16. var client = _clientFactory.CreateClient("csharpcorner");
  17. var response = await client.GetAsync(url);
  18. var result = await response.Content.ReadAsStringAsync();
  19. return result;
  20. }
  21. }
After running up this project and visiting it, we may get the following logs.
Using Retry Pattern In ASP.NET Core Via Polly
As you can see, it sends three requests to the link; the last two are triggered by retry policy.

Sending a message to the message bus

There are many message buses we can choose for our applications. Here, we will use RabbitMQ to show how to do that.
When our applications communicate with RabbitMQ, we should deal with the retry mechanism via conventional usage of Polly.
  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class ValuesController : ControllerBase
  4. {
  5. // GET api/values
  6. [HttpGet]
  7. public ActionResult<IEnumerable<string>> Get()
  8. {
  9. var message = Encoding.UTF8.GetBytes("hello, retry pattern");
  10. var retry = Policy
  11. .Handle<Exception>()
  12. .WaitAndRetry(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
  13. try
  14. {
  15. retry.Execute(() =>
  16. {
  17. Console.WriteLine($"begin at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}.");
  18. var factory = new ConnectionFactory
  19. {
  20. HostName = "localhost",
  21. UserName = "guest",
  22. Password = "guest"
  23. };
  24. var connection = factory.CreateConnection();
  25. var model = connection.CreateModel();
  26. model.ExchangeDeclare("retrypattern", ExchangeType.Topic, true, false, null);
  27. model.BasicPublish("retrypattern", "retrypattern.#", false, null, message);
  28. });
  29. }
  30. catch
  31. {
  32. Console.WriteLine("exception here.");
  33. }
  34. return new string[] { "value1", "value2" };
  35. }
  36. }
After running up this project and visiting it, we may get the following logs.
Using Retry Pattern In ASP.NET Core Via Polly

Summary

This article showed you two easy samples to use the retry pattern. Although it's very easy to use the retry pattern in our applications, we should consider where and when to use it but not everywhere. This is based on your business requirements.
I hope this article can help you!

Related Articles