Web API – How to use Polly library with Ocelot

In this post, we will see how to use the Polly library in the Microservices project created in the post: Web API – IHttpClientFactory.
But, what is the Polly library?
From the Official web site:
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.


To understand better how Polly can help us, we take the project and we disable the Microservice Api.Books:



Now, we run the project and, using Postman, we will call the Api.Orders through the Gateway:

Obviously, the service doesn’t work and we received an error.


The Polly library, can help us to avoid this type of problem and Ocelot use Polly to achieve the Quality Of Service, that is the ability to provide different priorities to different applications, users, or data flows, or to guarantee a certain level of performance to a data flow.
For this reason in Ocelot, is very easy to use Polly.

First of all, we open the Api.Gateway and we add the library Ocelot.Provider.Polly

Then, we open the ocelot.json file and we add the QoS Options for the Microservice Api.Books:

{
      "DownstreamPathTemplate": "/api/books/{id}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 56274
        }
      ],
      "UpstreamPathTemplate": "/api/books/{id}",
      "UpstreamHttpMethod": [ "GET" ],
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 1,
        "DurationOfBreak": 1000,
        // This value specifies that a request will automatically be timed out if it takes more than this value
        "TimeoutValue": 500
      }
    },


Now, we have to modify the method ConfigureServices in Startup.cs file:

public void ConfigureServices(IServiceCollection services)
{
      services.AddOcelot().AddPolly();
}



Finally, we have to modify the method GetOrdersAsync in Api.Orders\CoreOrder:

[CoreOrder.cs]

using Api.Orders.Core.Interfaces;
using Api.Orders.Db;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Api.Orders.Core.Providers
{
    public class CoreOrder : ICoreOrder
    {
        private readonly IBooksService booksService;
        private readonly ICustomersService customersService;

        public CoreOrder(IBooksService inputBooksService, ICustomersService inputCustomersService)
        {
            booksService = inputBooksService;
            customersService = inputCustomersService;
        }
        
        public async Task<(bool IsSuccess, IEnumerable<Order> Orders, string ErrorMessage)> GetOrdersAsync()
        {
            List<Order> lstOrder = new List<Order>();

            try
            {
                for (int i = 1; i < 6; i++)
                {
                    var objOrder = new Order();
                    objOrder.Id = i;
                    objOrder.OrderDate = DateTime.Now.AddDays(-i);
                    var resultCustomerService = await customersService.GetCustomer(i);
                    if (resultCustomerService.IsSuccess)
                    {
                        objOrder.EmailCustomer = resultCustomerService.ObjCustomer.Email;
                    }

                    var lstOrderItems = new List<OrderItem>();
                    for (int y = i; y < (i + 3); y++)
                    {
                        var orderItem = new OrderItem();
                        var resultBookService = await booksService.GetBook(y);
                        if (resultBookService.IsSuccess)
                        {
                            orderItem.BookTitle = resultBookService.ObjBook.Title;
                            orderItem.Price = resultBookService.ObjBook.Price;
                        }
                        else
                        {
                            orderItem.BookTitle = "Book information is not available";
                            orderItem.Price = 0;
                        }

                        orderItem.Quantity = y;
                        objOrder.Total = objOrder.Total + (orderItem.Price * orderItem.Quantity);

                        lstOrderItems.Add(orderItem);
                    }

                    objOrder.Books = new List<OrderItem>();
                    objOrder.Books.AddRange(lstOrderItems);

                    lstOrder.Add(objOrder);
                }

                return (true, lstOrder, null);
            }
            catch(Exception ex)
            {
                return (false, null, ex.Message);
            }
        }
    }
}


We have done and, if we run the application, this will be the result: