Given the following is set as the default for all clients in the C# project:
builder.Services.ConfigureHttpClientDefaults(http => {
// Turn on resilience by default
http.AddStandardResilienceHandler();
});
How does one override the values of that StandardResilienceHandler for a specific Client?
I've tried the following variations:
services.AddHttpClient<IMyClient, MyClient>()
.AddResilienceHandler("MyClient", (context, next) => {
context.AddTimeout(TimeSpan.FromMinutes(10));
});
ignored
.AddStandardResilienceHandler(options => {
options.AttemptTimeout = new HttpTimeoutStrategyOptions {
Timeout = TimeSpan.FromMinutes(5)
};
options.TotalRequestTimeout = new HttpTimeoutStrategyOptions {
Timeout = TimeSpan.FromMinutes(15)
};
options.CircuitBreaker.SamplingDuration = TimeSpan.FromMinutes(10);
});
Also ignored.
I also created a policy like this:
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
.WrapAsync(Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromMinutes(5),
TimeoutStrategy.Optimistic));
and then used this:
.AddPolicyHandler(retryPolicy)
It still uses the default no matter what.
You'd think this would be easy and documented but I can't find anything in search.
As far as I know you can't do what you want to achieve.
Whenever you call AddStandardResilienceHandler
or AddResilienceHandler
it registers a brand new ResilienceHandler
. That class is currently treated as internal. (So, calling it multiple times will register multiple ResilienceHandler
instances.)
You might have the temptation to retrieve the -standard
pipeline itself (that's the name of the pipeline which is registered by the AddStandardResilienceHandler
call) through the ResiliencePipelineProvider<string>
. The problem with that the retrieved ResiliencePipeline
it not adjustable directly. It only supports reload but that won't help you either...
So all in all, currently this use case is not supported. I would recommend to file an issue on the https://github.com/dotnet/extensions/issues repository.
UPDATE #1
Here is an example how to set and retrieve overridden value.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
var builder = Host.CreateApplicationBuilder(args);
builder.Services
.AddHttpClient("test")
.AddStandardResilienceHandler(options =>
{
options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(11);
});
var serviceProvider = builder.Services.BuildServiceProvider();
var monitor = serviceProvider.GetRequiredService<IOptionsMonitor<HttpStandardResilienceOptions>>();
var options = monitor.Get("test-standard");
Console.WriteLine(options.AttemptTimeout.Timeout);
using var host = builder.Build();
test
nameAttemptTimeout
from 10 seconds (the default) to 11IOptionsMonitor
from the DIHttpStandardResilienceOptions
which is named as test-standard
$"{httpClientName}-{pipelineIdentifier}"
pipelineIdentifier
is standard
If you use a typed client (instead of a named client) then the options name will be -standard
as mentioned in the original post.
Please note that you can override the options more or less independently. If you want to override AttemptTimeout
like in the above example then the rest of the options remain untouched.
I said more or less independently because for example you can't set the AttemptTimeout
to 20 seconds because it will throw an OptionsValidationException
due to misalignment with Circuit Breaker options:
Microsoft.Extensions.Options.OptionsValidationException
: The sampling duration of circuit breaker strategy needs to be at least double of an attempt timeout strategy’s timeout interval, in order to be effective. Sampling Duration: 30s,Attempt Timeout: 20s