-
Notifications
You must be signed in to change notification settings - Fork 8
Home
ThrottlingTroll works with ASP.NET Core, Azure Functions, Azure Functions with ASP.NET Core Integration and, in fact, can be used in any .NET project.
Depending on the platform your project is using, you need to install the correct ThrottlingTroll's NuGet package:
| ASP.NET Core | Azure Functions | Generic .NET | |
|---|---|---|---|
| Package: | ThrottlingTroll | ThrottlingTroll.AzureFunctions | ThrottlingTroll |
| Sources: | ThrottlingTroll.AspNet | ThrottlingTroll.AzureFunctions | ThrottlingTroll.Core |
| Samples: | ThrottlingTrollSampleWeb | ThrottlingTrollSampleFunction ThrottlingTrollSampleAspNetFunction ThrottlingTrollSampleInProcFunction ThrottlingTrollSampleDotNet6InProcDurableFunction | (no dedicated sample project yet) |
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.
Just create an instance of ThrottlingTroll class and provide rules and limits as ctor's parameters.
Alternatively, use .AddThrottlingTroll() extension method to add an instance of IThrottlingTroll to your DI container. This option will also automatically pick rules and limits from your app config.
Then use IThrottlingTroll.WithThrottlingTroll() methods to limit your payloads.
- FixedWindow.
- SlidingWindow.
- LeakyBucket.
- Semaphore aka Concurrency Limiter.
- CircuitBreaker.
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.
Since version 7.3 ThrottlingTroll is instrumented with OpenTelemetry. Here is how to subscribe to ThrottlingTroll's metric and trace sources:
var otel = builder.Services.AddOpenTelemetry();
otel.WithMetrics(metrics =>
{
//...
metrics.AddMeter("ThrottlingTroll");
});
otel.WithTracing(tracing =>
{
//...
tracing.AddSource("ThrottlingTroll");
});
, then configure an exporter to your favourite observability tool - and you should see ThrottlingTroll's metrics and traces there.
Here is a sample trace (as it appears in Azure Monitor):

List of metrics (counters) emitted by ThrottlingTroll's meter:
-
throttlingtroll.ingress.rules_matched- counts how many rate limiting rules were matched by incoming requests. -
throttlingtroll.ingress.requests_throttled- counts how many incoming requests were throttled (hit the limit). -
throttlingtroll.egress.rules_matched- counts how many rate limiting rules were matched by outgoing requests. -
throttlingtroll.egress.requests_throttled- counts how many outgoing requests were throttled (hit the limit). -
throttlingtroll.internal_failures- counts how many internal failures ThrottlingTroll experienced. -
throttlingtroll.get_config_func_successes- counts how many times ThrottlingTrollOptions.GetConfigFunc was successfully called. -
throttlingtroll.get_config_func_failures- counts how many times ThrottlingTrollOptions.GetConfigFunc failed.