Rate Limit Hook
The RateLimitInteractionHook prevents flooding a user's inbox with too many simultaneous interactions. It enforces per-user rate limits on both the number of interactions per minute and the maximum concurrent pending interactions.
Rate Limits Enforced
| Limit | Default | Configuration Key |
|---|---|---|
| Interactions per minute per user | 5 | RateLimiting.MaxPerMinutePerUser |
| Concurrent pending interactions per user | 10 | RateLimiting.MaxConcurrentPerUser |
| Burst allowance (above the per-minute limit) | 2 | RateLimiting.BurstAllowance |
Configuration
// appsettings.json
{
"EdgeInteract": {
"RateLimiting": {
"MaxPerMinutePerUser": 5,
"MaxConcurrentPerUser": 10,
"BurstAllowance": 2,
"ExemptTypes": ["notification"]
}
}
}
// Registration
builder.Services.AddInteractionHook<RateLimitInteractionHook>();
What Happens When the Limit Is Hit
When a publish attempt exceeds a rate limit, the hook throws InteractionRateLimitException:
// Thrown by RateLimitInteractionHook
public class InteractionRateLimitException : InteractionBlockedException
{
public string UserId { get; }
public string LimitType { get; } // "per_minute" | "concurrent"
public int CurrentCount { get; }
public int Limit { get; }
public TimeSpan RetryAfter { get; }
}
The pipeline catches this and returns a 429 Too Many Requests-equivalent error to the caller of PublishAndWaitAsync().
Exempt Interaction Types
Some interaction types (e.g., notification) are typically lower-priority and higher-volume. You can exempt specific types from rate limiting:
options.AuditLog.ExemptTypes = ["notification", "my-company/info-banner"];
High-Priority Override
Interactions with priority: "high" are granted additional burst allowance equal to the BurstAllowance setting. This allows critical approvals to break through a high-volume inbox without completely bypassing rate limits.
IInteractionHook with your own logic and register it before RateLimitInteractionHook. See the Custom Hooks page for the implementation pattern.
Distributed Rate Limiting
In multi-instance deployments, the rate limit counters are backed by a distributed cache (Redis by default when available, in-memory otherwise). This ensures the limit is applied globally across all server instances, not per-instance:
// Configuration for Redis-backed distributed rate limiting
builder.Services.AddStackExchangeRedisCache(options => {
options.Configuration = "redis-host:6379";
});
builder.Services.AddInteractionHook<RateLimitInteractionHook>(); // auto-uses Redis if registered