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).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int _requestCount = 0;

app.MapGet("/Inventory/{id}", async (int id) =>
{
    _requestCount++;

    await Task.Delay(TimeSpan.FromSeconds(1));
    if (_requestCount % 4 == 0) // only one of out four requests will succeed
    {
        System.Console.WriteLine($"{_requestCount} It worked!");
        return Results.Ok(15);
    }

    System.Console.WriteLine($"{_requestCount} Something went wrong");
    return Results.Problem("Something went wrong");
});

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
app.MapGet("/Catalog/{id}", async (int id, IAsyncPolicy<HttpResponseMessage> policy) =>
{
    var cts = new CancellationTokenSource(3000);
    var cancellationToken = cts.Token;

    HttpClient httpClient = new HttpClient()
    {
        BaseAddress = new System.Uri(@"http://localhost:5000/")
    };
    string requestEndpoint = $"Inventory/{id}";

    HttpResponseMessage response;
    try
    {
        response = await policy.ExecuteAsync((ct) => 
            httpClient.GetAsync(requestEndpoint, ct), cancellationToken);
    }
    catch (OperationCanceledException oce)
    {
        System.Console.WriteLine($"Request timed out, the cancellation token was triggered. {oce.Message}");
        return Results.Problem($"Request timed out, the cancellation token was triggered. {oce.Message}");
    }

    if (response.IsSuccessStatusCode)
    {
        int itemsInStock = await response.Content.ReadFromJsonAsync<int>();
        return Results.Ok(itemsInStock);
    }
    return Results.Problem("Something went wrong calling the inventory endpoint");
});
 
That’s all there is to it.

The attached zip file has the full source code.

Download full source code.

comments powered by Disqus

Related