-
Notifications
You must be signed in to change notification settings - Fork 3
Home
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.
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:
- Declaratively, aka using ThrottlingTrollAttribute. Aims for best readability.
-
Statically, aka via
appsettings.json/host.json
. Simplest. - Programmatically, at startup. 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.
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.
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.
- FixedWindow.
- SlidingWindow.
- Semaphore aka Concurrency Limiter.
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:
- ThrottlingTroll.CounterStores.Redis
- ThrottlingTroll.CounterStores.DistributedCache
- ThrottlingTroll.CounterStores.AzureTable
- ThrottlingTroll.CounterStores.EfCore
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:
builder.Services.AddSingleton<ICounterStore>(
provider => new MyCounterStore(...)
);
app.UseThrottlingTroll(options =>
{
options.CounterStore = new MyCounterStore(...);
});
NOTE, that ICounterStore implementations are supposed to be thread-safe.
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}");
};
});
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.