[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
Poll updates with no sender) share bucket 0 for that scope. For Global, all calls share a single bucket.
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 toLimit), 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:
- A request that does not match the command/pattern/state checks never consumes quota.
- Throttled calls skip filter resolution and DI service activation entirely — no handler services are injected.
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
CUR035 – Invalid or non-constant throttle configuration
CUR035 – Invalid or non-constant throttle configuration
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).