Skip to content
Konstantin Lepeshenkov edited this page Jun 1, 2024 · 39 revisions

Installing from NuGet

ThrottlingTroll works with ASP.NET Core, Azure Functions (.NET Isolated) and Azure Functions with ASP.NET Core Integration.

Depending on the platform your project is using, you need to install the correct ThrottlingTroll's NuGet package:

ASP.NET Core Azure Functions Azure Functions with ASP.NET Core Integration
Package: ThrottlingTroll ThrottlingTroll.AzureFunctions ThrottlingTroll.AzureFunctionsAspNet
Sources: ThrottlingTroll.AspNet ThrottlingTroll.AzureFunctions ThrottlingTroll.AzureFunctionsAspNet
Samples: ThrottlingTrollSampleWeb ThrottlingTrollSampleFunction ThrottlingTrollSampleDotNet6InProcDurableFunction ThrottlingTrollSampleAspNetFunction

To see whether your Functions project uses ASP.NET Core Integration, check your startup code. ASP.Net Core Integration projects usually contain .ConfigureFunctionsWebApplication() setup method there.

Note that egress rate limiting functionality (self-limiting HttpClient) can actually be used in any .NET project, and for that you just need to install this ThrottlingTroll package.

[Ingress] How to initialize and configure

You will need to call one or another form of .UseThrottlingTroll() method at your service's startup. Which version of it to call depends on which way of configuring rules/limits/settings you prefer. Four different ways are supported:

You can combine all four approaches in the same solution - ThrottlingTroll will just make up an aggregate of all rules and settings configured in one way or another. E.g. it might be useful to define some global limits statically or declaratively, and then fine-tune them on-the-go via a GetConfigFunc.

The current effective set of rules and settings is always available to your code via this.HttpContext.GetThrottlingTrollConfig() or request.FunctionContext.GetThrottlingTrollConfig() extension methods.

[Egress] How to initialize and configure

ThrottlingTroll allows you to configure and use a self-limiting HttpClient (the one that automatically returns an error response without making the actual HTTP call, once a configured limit is exceeded). You can initialize those HttpClient instances in three different ways:

  • Statically, aka via appsettings.json/host.json. Simplest.
  • Programmatically. Allows to have any kind of complicated initialization logic.
  • Reactively. You provide a routine, that fetches limits from wherever, and an IntervalToReloadConfigInSeconds for that routine to be called periodically by ThrottlingTroll. Allows to reconfigure rules and limits on-the-fly, without restarting your service.

Note that if Algorithm value is not specified in config settings, the default FixedWindow will be used.

By default, counters are stored in MemoryCacheCounterStore (in local memory).

Other out-of-the-box Counter Stores are:

You can use one of them, or you can create and use your own custom implementation of ICounterStore interface.

To configure a Counter Store to be used:

EITHER put an instance of it into your DI container:

builder.Services.AddSingleton<ICounterStore>(
    provider => new MyCounterStore(...)
);

OR provide it via UseThrottlingTroll() method:

app.UseThrottlingTroll(options =>
{
    options.CounterStore = new MyCounterStore(...);
});

NOTE, that ICounterStore implementations are supposed to be thread-safe.

Logging

By default, ThrottlingTroll will try to get and use an ILogger instance from your DI container.

Instead you can provide your custom logging routine, e.g.:

app.UseThrottlingTroll(options =>
{
    options.Log = (level, msg) => 
    {
        Console.WriteLine($"Severity: {level}. Message: {msg}");
    };
});

Exception handling

The way internal ThrottlingTroll's exceptions are handled is controlled by RateLimitMethod.ShouldThrowOnFailures setting.

For most rate limiting algorithms the default value for that setting is false, but for Semaphore rate limiter the default value is true. You can always configure this value explicitly:

app.UseThrottlingTroll(options =>
{
    // ...

    options.Config = new ThrottlingTrollConfig
    {
        Rules = new[]
        {
            new ThrottlingTrollRule
            {
                LimitMethod = new FixedWindowRateLimitMethod
                {
                    PermitLimit = 1,
                    IntervalInSeconds = 2,
                    ShouldThrowOnFailures = true
                }
            }
        }
    };

    // ...
});

When ShouldThrowOnFailures is set to false, ThrottlingTroll will log its internal exceptions and allow the request to be further processed. This means that, if e.g. you are using Redis counter store and your Redis instance is malfunctioning, the rate limiting will not be applied.

When ShouldThrowOnFailures is set to true, ThrottlingTroll will log and rethrow its internal exceptions. This means that, if e.g. you are using Redis counter store and your Redis instance is malfunctioning, your service will be broken.