Polly with .NET 6, Part 5 - Using a Cancellation Token
Download full source code.
Want to learn more about Polly? Check out my Pluralsight course on it.
This is a quick post to show you how to use Polly with .NET 6 to make a web service request that can be canceled if it is taking too long.
With the cancellation token, the current request will be canceled, and any remaining retries will be abandoned.
I am reusing code from earlier posts on Polly and .NET 6, so I not going to explain everything in detail.
The retry policy
I have a simple retry policy that will retry a request up to 3 times.
builder.Services.AddSingleton<IAsyncPolicy<HttpResponseMessage>>(
Policy.HandleResult<HttpResponseMessage>(
r => !r.IsSuccessStatusCode).RetryAsync(3));
An endpoint that fails
Here is a simple endpoint that fails 75% of the time, and responds slowly (note the one second delay on line 7).
1int _requestCount = 0;
2
3app.MapGet("/Inventory/{id}", async (int id) =>
4{
5 _requestCount++;
6
7 await Task.Delay(TimeSpan.FromSeconds(1));
8 if (_requestCount % 4 == 0) // only one of out four requests will succeed
9 {
10 System.Console.WriteLine($"{_requestCount} It worked!");
11 return Results.Ok(15);
12 }
13
14 System.Console.WriteLine($"{_requestCount} Something went wrong");
15 return Results.Problem("Something went wrong");
16});
An endpoint that calls the failing endpoint
Here is an endpoint that calls the failing endpoint, and uses the retry policy to retry the request.
It also uses a cancellation token to cancel the request if it takes too long. In this case, the request will be canceled after 3 seconds, any remaining retries will also be abandoned.
The cancellation token is passed to the policy.ExecuteAsync
method on lines 15/16.
1app.MapGet("/Catalog/{id}", async (int id, IAsyncPolicy<HttpResponseMessage> policy) =>
2{
3 var cts = new CancellationTokenSource(3000);
4 var cancellationToken = cts.Token;
5
6 HttpClient httpClient = new HttpClient()
7 {
8 BaseAddress = new System.Uri(@"http://localhost:5000/")
9 };
10 string requestEndpoint = $"Inventory/{id}";
11
12 HttpResponseMessage response;
13 try
14 {
15 response = await policy.ExecuteAsync((ct) =>
16 httpClient.GetAsync(requestEndpoint, ct), cancellationToken);
17 }
18 catch (OperationCanceledException oce)
19 {
20 System.Console.WriteLine($"Request timed out, the cancellation token was triggered. {oce.Message}");
21 return Results.Problem($"Request timed out, the cancellation token was triggered. {oce.Message}");
22 }
23
24 if (response.IsSuccessStatusCode)
25 {
26 int itemsInStock = await response.Content.ReadFromJsonAsync<int>();
27 return Results.Ok(itemsInStock);
28 }
29 return Results.Problem("Something went wrong calling the inventory endpoint");
30});
That’s all there is to it.
The attached zip file has the full source code.
Download full source code.