I have a project that calls many rest APIs from other projects, and I have some problems to identify not only errors from those APIs but also correct responses but the information is not correct on the other system. I did this part, but it only log the retry and I need to log the success also.
services.AddHttpClient<IClient, Client>("AuthClient", x =>
{
x.BaseAddress = new Uri(urlAn);
}).AddPolicyHandler((services, request) =>
HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(
new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
},
onRetry: (outcome, timespan, retryAttempt, context) =>
{
services.GetService<ILogger>()
.LogWarning("Delaying for {delay}ms, then making retry {retry}.", timespan.TotalMilliseconds, retryAttempt);
}));
The onRetry
method is executed only if there was an error, which is handled by the policy.
TheHandleTransientHttpError
triggers the policy
HttpRequestException
To inject a logic which should be executed in every situation you need to make use of a custom DelegatingHandler
. This extension point let's you inject custom code into the HttpClient's pipeline (1).
Here is a naive implementation of a LoggerHandler
:
class LoggerHandler: DelegatingHandler
{
private readonly ILogger<LoggerHandler> _logger;
public LoggerHandler(ILogger<LoggerHandler> logger)
{
_logger = logger;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
var response = await base.SendAsync(request, cancellationToken);
_logger.LogInformation(response.StatusCode.ToString());
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Request has failed after several retries");
throw;
}
}
}
Now, let's wire up all the things:
var retryPolicy = HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(
new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
});
services.AddHttpClient<IClient, Client>("AuthClient", x => { x.BaseAddress = new Uri(urlAn); })
.AddPolicyHandler(retryPolicy)
.AddHttpMessageHandler<LoggerHandler>();
Please bear in mind the registration order matters.
There are several tiny things that could be improved as well:
HttpClient
, because you are using Typed-Client.
services.AddHttpClient<IClient, Client>(x => ...)
IClient
and Client
. Image a situation that you need to add one more client to your app. How would name that? AuthClient
might be a better name:
services.AddHttpClient<IAuthClient, AuthClient>(x => ...)