Skip to main content
PolyBot provides declarative sliding-window rate limiting through the [Throttled] attribute. The source generator inlines a ThrottleGate.TryEnter guard directly into the handler’s routing branch — after the command/pattern/state match guards pass, but before filter resolution or handler invocation — so non-matching updates never consume budget and throttled calls short-circuit with zero extra allocations beyond the gate’s bookkeeping.

The [Throttled] attribute

Properties

ThrottleScope — bucketing strategies

Updates whose identity cannot be resolved (e.g. Poll updates with no sender) share bucket 0 for that scope. For Global, all calls share a single bucket.
Prefer ThrottleScope.User for commands that are expensive per caller. Use ThrottleScope.Global for handlers that hit shared external resources (API quotas, database write limits).

ThrottleAction — behavior on exhaustion

Ignore is useful when you want to silently discard excess calls. Fallthrough lets you route over-limit requests to a fallback handler — for example, to reply with a “please slow down” message.

Implementation details

Gates are static per handler and instantiated once at application startup. Thread-safety is achieved with a single lock over per-bucket ring buffers. Buckets hold only timestamps of recent calls (sized to Limit), so memory is bounded. The guard is inlined after command/pattern/state match guards pass and before filter resolution and DI service injection. This means:
  1. A request that does not match the command/pattern/state checks never consumes quota.
  2. Throttled calls skip filter resolution and DI service activation entirely — no handler services are injected.
Buckets are never evicted. Long-running bots with a very large number of distinct users and ThrottleScope.User will accumulate one bucket entry per user. For bots with millions of users, consider a scope with fewer distinct keys (e.g. Global) or implement a custom rate-limiter outside PolyBot.

Example: burst limiter

Diagnostics reference

Severity: WarningOne or more [Throttled] properties (Limit, PeriodMilliseconds, Scope, or Action) are non-constant or hold an invalid value. The offending values are clamped to their defaults (Limit = 1, PeriodMilliseconds = 1000, Scope = User, Action = Ignore).