Resilient Modern Apps with Polly in .NET - Retry Pattern
Resilient Modern Apps with Polly in .NET - Retry Pattern
• .NET
• 5 min read
Modern Apps should be resilient, catering for transient faults when communicating with services. In this post, the retry pattern1 is implemented with the help of Polly Retry and Polly Await Retry policies.
For more details about Polly Retry, please check their documentation2. In all examples below, the Microsoft.Extensions.Http.Polly NuGet package version 7.0.10 was used.
Polly Retry
Sometimes a brute force approach to get the information does the job, and for that, Polly provides a Retry policy that allows for multiple contiguous retries.
The UML sequence diagram above shows the case of HTTP 429 (Too Many Requests) responses.
The code example below is extracted from an Azure Function Consumer project that is using a Typed HttpClient to communicate with an external service. The Polly Retry policy is applied to the HttpClient, and it will retry 3 times if the response is not successful.
Depending on the transient fault, contiguous retries may not work, especially if the service is unavailable. It is advisable to try, and wait a bit before retrying it. Polly provides a Wait and Retry policy that allows for multiple contiguous retries with a delay between them.
The UML sequence diagram above shows the case of HTTP 503 (Service Unavailable) responses.
The code example below is extracted from another Azure Function Consumer project that is using the same Typed HttpClient to communicate with an external service. The Polly Await Retry policy is applied to the HttpClient, and it will retry 3 times with an interval of 1000 milliseconds (1 second) if the response is not successful.
The Polly Await Retry policy can be improved by adding jitter to the delay between retries. This will help to avoid multiple clients retrying at the same time, and it will help to avoid the Thundering Herd3 problem.
The jitter strategy4 can help to evenly distribute the load across the clients, and it can be applied to the Polly Await Retry policy as below:
The above implementation leverages Polly.Contrib.WaitAndRetry NuGet package version 1.1.1, and the sample code is available on PlayGoKids repository
Simulating the transient fault
The Azure Function Producer project, which is basically a Counter, simulates transient faults. It is responsible for preserving and incrementing the counter state.
[Function(nameof(Increment))]publicHttpResponseDataIncrement([HttpTrigger(AuthorizationLevel.Function,"get")]HttpRequestDatareq){_logger.LogInformation("Request to increment counter.");varisFailureEnabled=_configuration.GetValue<bool>(Constants.FailureEnabled);// variable to control failure injectionvarcurrentCounter=_tableStorageHelper.GetCounter(Constants.Counter,Constants.PartitionKey,Constants.Row);if(isFailureEnabled&¤tCounter%3==0){conststringerrorMessage="Counter is divisible by 3, throwing exception.";_logger.LogError(errorMessage);thrownewException(errorMessage);}varcounter=_tableStorageHelper.IncrementCounter(Constants.Counter,Constants.PartitionKey,Constants.Row);varresponse=req.CreateResponse(HttpStatusCode.OK);response.Headers.Add("Content-Type","text/plain; charset=utf-8");varmessage=$"Current counter: {counter}";_logger.LogInformation(message);response.WriteString(message);returnresponse;}
This Increment function is used to increment a counter, and depending on a condition it simulates a transient fault by throwing an exception when the counter is divisible by 3. The isFailureEnabled variable comes from the settings.json file, and it is also used to control the failure injection.
To be able to run it on your machine, make sure the Table Storage is initialized as below:
Join the conversation! Share your thoughts and connect with other readers.