Search code examples
c#dotnet-httpclientrate-limitingpolly

Microsoft.Extensions.Http.Resilience: Using AddStandardResilienceHandler options with SlidingWindowRateLimiter


Using Microsoft.Extensions.Http.Resilience is it possible to use precise RateLimiter options, such as SlidingWindowRateLimiter, with the AddStandardResilienceHandler. Alternatively apply the defaults from AddStandardResilienceHandler to a custom AddResilienceHandler definition for everything else other than the RateLimiter part?

Ideally I'd like to use the best practice defaults that are built-in to the resilience library, but override the RateLimiter part for specific API imposed limits.

For example I'd like to combine:

builder.AddStandardResilienceHandler(static options => {
    // Either apply RateLimiter options from below
});

with RateLimiter options such as:

services.AddHttpClient(Constants.StarshipitHttpClient)
    .AddResilienceHandler(Constants.StarshipitHttpClient, static builder =>
    {
        builder.AddRateLimiter(new SlidingWindowRateLimiter(
            new SlidingWindowRateLimiterOptions
            {
                PermitLimit = 2,
                Window = TimeSpan.FromSeconds(1),
                QueueLimit = int.MaxValue,
            }
        ));

        // Or add other default resiliency options from AddStandardResilienceHandler above  
    });

Does anyone know how to achieve this?


Solution

  • Ideally it should be as easy as this:

    .AddStandardRResilienceHandler(options => 
    { 
       options.RateLimiter = yourRateLimiterOptions; 
    })
    

    But as far as I can see the the reported issue to alter default values is not yet fixed as of writing this answer.


    For named HttpClient it works like this

    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();
    
    • It registers a named HttpClient with test name
    • It adds the standard resilience handler to it
    • It overrides the AttemptTimeout from 10 seconds (the default) to 11
    • It retrieves an IOptionsMonitor from the DI
    • It retrieves that HttpStandardResilienceOptions which is named to test-standard

    The printed output will be 11 seconds, see related dotnet fiddle

    The same should work for the RateLimiter property.