In short: I want to execute X-HttpMessageHandlers when retrying a request.
Implementation: Currently, I have added an HttpClient, whose request gets handled by a Logging- and a PolicyHandler:
using Microsoft.Extensions.Http.Polly
builder.Services.AddHttpClient()
.AddHttpMessageHandler<LoggingHandler>()
.AddPolicyHandler(GetRetryPolicy());
Policy: To keep the policy very simple, let's use an example:
public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
// HandleTransientHttpError: Handles HttpRequestException,
// Http status codes >= 500 (server errors)
// and status code 408 (request timeout)
return HttpPolicyExtensions
.HandleTransientHttpError()
.RetryAsync(3); // Retry the request up to 3 times
}
In case you want to test out the retry policy, send requests to: https://httpbin.org/status/503.
The above link will return an unsuccessful HttpResponseMessage with a status code 502, aka Bad Gateway. This response type is a server error, so it will get handled by the policy.
Sources:
TL; DR: You just have to change the message handlers registration order
from
.AddHttpMessageHandler<LogHandler>()
.AddPolicyHandler(retryPolicy);
to
.AddPolicyHandler(retryPolicy)
.AddHttpMessageHandler<LogHandler>();
UPDATE #1
In order to better understand why DelegatingHandler
s' registration order matter I will extend my original post.
AddPolicyHandler
This extension method basically registers a PolicyHttpMessageHandler
instance into the handlers pipeline. This class implements the DelegatingHandler
abstract class in a way that it applies a policy to the outgoing request. That's why the policy's type should be IAsyncPolicy<HttpResponseMessage>
.
The important stuff here is that from the HttpClient
perspective your LogHandler
and this PolicyHttpMessageHandler
are treated in the same way.
AddHttpMessageHandler
, AddPolicyHandler
If you register the handlers into the HttpClient's pipeline like you did then the output will be:
Loghandler
Retry attempt 1
Retry attempt 2
Lets see what happens under the hood
I've used mermaid.js to draw this diagram and I've used autonumbering to be able to correlate action and emitted output.
2: Loghandler
7: Retry attempt 1
10: Retry attempt 2
AddPolicyHandler
,AddHttpMessageHandler
This time lets switch the registration order. The output will be:
Loghandler
Retry attempt 1
Loghandler
Retry attempt 2
Loghandler
The actions sequence:
and finally the correlated log:
4: Loghandler
8: Retry attempt 1
10: Loghandler
14: Retry attempt 2
16: Loghandler
For more details please check out this SO topic.
Here you can find a dotnet fiddle to be able to play with it.