Building resilient .NET applications with Polly - Part 3

In this post, we will establish a straightforward Azure Functions setup that makes requests to an external service. Subsequently, we will scrutinize the behavior of this function when the external service encounters a breakdown.

Installing the environment

Deploying the flawed service

  • Create a new solution and add a new Azure Function project named EOCS.Polly.FaultyService in it.

  • Add a new class named FaultyService.cs for example and the following code to it.

 1public class FaultyService
 2{
 3    public FaultyService()
 4    {
 5    }
 6
 7
 8    [FunctionName(nameof(GetNeverResponding))]
 9    public async Task<IActionResult> GetNeverResponding([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
10    {
11        while (true)
12        {
13
14        }
15
16        return new OkResult();
17    }
18}
Information

Indeed, this code lacks significant complexity, with its only noteworthy aspect being that the request never concludes.

  • Add a new class named StartUp.cs and the following code to it.
 1[assembly: WebJobsStartup(typeof(StartUp))]
 2namespace EOCS.Polly.FaultyService
 3{
 4    public class StartUp : FunctionsStartup
 5    {
 6        public override void Configure(IFunctionsHostBuilder builder)
 7        {            
 8        }
 9    }
10}
  • Run the program and note the url.

Deploying the calling service

  • In the same solution, add a new Azure Function project named EOCS.Polly.CallingService.

  • Add a new class named CallingService.cs for example and the following code to it.

 1public class CallingService
 2{
 3    public CallingService()
 4    {
 5    }
 6
 7
 8    [FunctionName(nameof(GetAccountById))]
 9    public async Task<IActionResult> GetAccountById([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
10    {
11        var client = new HttpClient();
12        var response = await client.GetAsync("http://localhost:7271/api/GetNeverResponding");
13
14        return new OkResult();
15    }
16}
Information 1

In a real-world scenario, the URL should be stored in the configuration file and obtained through dependency injection.

Information 2

The code above simply initiates an HTTP request to our flawed service. The objective is to examine the consequences when a service becomes unresponsive.

  • Add a new class named StartUp.cs and the following code to it.
 1[assembly: WebJobsStartup(typeof(StartUp))]
 2namespace EOCS.Polly.CallingService
 3{
 4    public class StartUp : FunctionsStartup
 5    {
 6        public override void Configure(IFunctionsHostBuilder builder)
 7        {            
 8        }
 9    }
10}

The final configuration should resemble the picture below.

Important

Do not forget to correctly configure the startup projects.

Running the application

We will now test our application by executing a GET request through Fiddler (or Postman) and observe the ensuing results.

  • Start the application.

  • Execute the following request.

It's evident that this request appears to be without a response.

What is transpiring aligns precisely with what we illustrated earlier: the calling thread is suspended due to a downstream service experiencing a delay. How to address such a situation ? Polly to the rescue !

What is Polly ?

Polly is a resilience and transient-fault-handling library designed to help developers handle faults in their applications by providing policies to define and implement fault-handling logic. Polly allows developers to define strategies for various scenarios, such as handling transient faults, retries, timeouts, and circuit breaking (more on this in the subsequent posts).

Polly is particularly beneficial in the context of microservices and we will now explore its practical implementation.

Building resilient applications with Polly - Part 4