Configuration
This guide covers all configuration options available in RateLimitHeaders.
Handler Options
The RateLimitHandlerOptions class configures the DelegatingHandler:
| Property | Type | Default | Description |
|---|---|---|---|
EnableProactiveThrottling |
bool |
false |
Enable automatic request delays when quota is low |
QuotaLowThreshold |
double |
0.1 |
Threshold (0-1) for triggering quota low warnings |
ThrottlingAlgorithm |
IThrottlingAlgorithm |
PercentageThrottlingAlgorithm |
Algorithm for calculating throttle delays |
StateKeyExtractor |
Func<HttpRequestMessage, string> |
Hostname | Function to extract state tracking key from requests |
OnRateLimitInfo |
Func<RateLimitInfoEventArgs, ValueTask>? |
null |
Callback when rate limit headers are parsed |
OnQuotaLow |
Func<QuotaLowEventArgs, ValueTask>? |
null |
Callback when quota falls below threshold |
OnThrottling |
Func<ThrottlingEventArgs, ValueTask>? |
null |
Callback before a request is throttled |
Proactive Throttling
When EnableProactiveThrottling is true, the handler automatically delays requests when quota is low:
options.EnableProactiveThrottling = true;
options.ThrottlingAlgorithm = new PercentageThrottlingAlgorithm(
threshold: 0.1, // Start throttling at 10% remaining
factor: 1.0, // Delay multiplier
maxDelay: TimeSpan.FromSeconds(5));
PercentageThrottlingAlgorithm
The default algorithm calculates delays as:
Delay = (threshold - remainingPercentage) * resetSeconds * factor
| Parameter | Default | Description |
|---|---|---|
threshold |
0.1 |
Start throttling when remaining quota falls below this percentage |
factor |
1.0 |
Multiplier for calculated delay |
maxDelay |
5 seconds |
Maximum delay to apply |
State Key Extraction
By default, rate limit state is tracked per hostname:
// Default: hostname only
// api.example.com/v1/users -> "api.example.com"
// api.example.com/v1/orders -> "api.example.com"
Customize state key extraction for more granular tracking:
// Track per path segment
options.StateKeyExtractor = request =>
{
var uri = request.RequestUri;
if (uri is null) return "default";
var segments = uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
return segments.Length > 0 ? $"{uri.Host}/{segments[0]}" : uri.Host;
};
// Track per API key
options.StateKeyExtractor = request =>
{
var apiKey = request.Headers.TryGetValues("X-API-Key", out var values)
? values.FirstOrDefault()
: null;
var host = request.RequestUri?.Host ?? "default";
return apiKey is not null ? $"{host}:{apiKey}" : host;
};
Partition Key Considerations
Some APIs partition rate limits by tenant, user, or API key (indicated by the pk parameter in response headers). The library parses this value into RateLimitInfo.PartitionKey, but proactive throttling does not automatically use it because:
- The state key must be computed before sending the request
- The partition key is only known after receiving the response
Use StateKeyExtractor to include the partition identifier from your request if your API uses partition-based rate limiting.
Event Callbacks
OnRateLimitInfo
Called whenever rate limit headers are successfully parsed:
options.OnRateLimitInfo = args =>
{
metrics.RecordRateLimit(
args.RateLimitInfo.PolicyName,
args.RateLimitInfo.Remaining,
args.RateLimitInfo.Quota);
return ValueTask.CompletedTask;
};
OnQuotaLow
Called when remaining quota falls below QuotaLowThreshold:
options.OnQuotaLow = args =>
{
alertService.SendAlert(
$"API quota at {args.RemainingPercentage:P0}",
args.RequestUri);
return ValueTask.CompletedTask;
};
OnThrottling
Called before a request is throttled (when proactive throttling is enabled):
options.OnThrottling = args =>
{
logger.LogInformation(
"Throttling request to {Uri} for {Delay}ms: {Reason}",
args.RequestUri,
args.Delay.TotalMilliseconds,
args.Reason);
return ValueTask.CompletedTask;
};
IETF RateLimit Headers
The library parses headers according to draft-ietf-httpapi-ratelimit-headers-10:
RateLimit: "default";r=50;t=30
RateLimit-Policy: "default";q=100;w=60
| Header | Format | Description |
|---|---|---|
RateLimit |
"policy";r=remaining;t=reset |
Current rate limit state |
RateLimit-Policy |
"policy";q=quota;w=window |
Rate limit policy definition |
Parsed Values
| Property | Description |
|---|---|
PolicyName |
The rate limit policy name (e.g., "default", "api-v2") |
Remaining |
Requests remaining in the current window |
ResetSeconds |
Seconds until the window resets |
Quota |
Maximum requests allowed per window |
WindowSeconds |
Duration of the rate limit window |
PartitionKey |
Optional partition key from pk parameter |
IsValid |
Whether at least one header was successfully parsed |
Thread Safety
The library is designed to be thread-safe:
RateLimitInfois a readonly struct (immutable)- State tracking uses
ConcurrentDictionary - Handlers are transient (as required by IHttpClientFactory)
Polly-Specific Options
When using with Polly, the same options apply via RateLimitHeadersOptions:
var pipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddRateLimitHeaders(options =>
{
options.EnableProactiveThrottling = true;
options.QuotaLowThreshold = 0.1;
options.OnRateLimitInfo = args => { /* ... */ };
})
.Build();
Rate limit info is stored in the ResilienceContext and can be accessed via:
context.Properties.TryGetValue(RateLimitContextProperties.RateLimitInfoKey, out var info);