Token Bucket
The token bucket classes that power Choked’s dual rate limiting functionality.Overview
Choked uses two different token bucket implementations depending on your backend configuration:- RedisTokenBucket: For distributed rate limiting using Redis
- ProxyTokenBucket: For managed rate limiting via the Choked proxy service
Choked class configuration. You typically don’t need to use these classes directly.
RedisTokenBucket
Used when aChoked instance is created with redis_url. Provides distributed coordination using Redis with atomic Lua scripts.
Constructor
Unique identifier for the rate limit bucket
Maximum number of request tokens in the bucket (0 = no request limiting)
Rate at which request tokens are added to the bucket (tokens per second, 0.0 = no request limiting)
Maximum number of content tokens in the bucket (0 = no token limiting)
Rate at which content tokens are added to the bucket (tokens per second, 0.0 = no token limiting)
Redis connection URL. If not provided, uses the redis_url from the parent Choked instance.
Methods
acquire()
requests_needed(int): Number of request tokens to acquire (typically 1)tokens_needed(int): Number of content tokens to acquire (estimated from function args)
True if both types of tokens were successfully acquired, False otherwise.
Behavior:
- Both request and token buckets are checked atomically
- If either bucket lacks sufficient tokens, no tokens are consumed
- Buckets are refilled based on elapsed time since last access
- Uses Redis Lua scripts for atomic operations
Configuration
Requires Redis connection via the parentChoked instance:
Redis Storage
The Redis implementation stores:- Request bucket state:
{key}:requests(current tokens, last refill time) - Token bucket state:
{key}:tokens(current tokens, last refill time) - Uses Redis Hash data type for efficient storage
- Atomic operations via Lua scripts prevent race conditions
ProxyTokenBucket
Used when aChoked instance is created with api_token. Provides managed rate limiting through the Choked proxy service.
Constructor
API token for the Choked proxy service
Unique identifier for the rate limit bucket
Maximum number of request tokens in the bucket (0 = no request limiting)
Rate at which request tokens are added to the bucket (tokens per second, 0.0 = no request limiting)
Maximum number of content tokens in the bucket (0 = no token limiting)
Rate at which content tokens are added to the bucket (tokens per second, 0.0 = no token limiting)
Methods
acquire()
requests_needed(int): Number of request tokens to acquiretokens_needed(int): Number of content tokens to acquire
True if tokens were successfully acquired, False otherwise.
Behavior:
- Makes HTTP request to proxy service
- Service handles bucket logic server-side
- Automatic retry on network failures
- No local state storage required
Configuration
Requires API token for the managed service. Contact us for access.Network Behavior
- HTTP-based communication with proxy service
- Automatic retries on network failures
- Respects standard HTTP timeouts
- Falls back gracefully on service unavailability
Usage Notes
Automatic Instantiation
Token buckets are automatically created by theChoked decorator:
Rate Limit Conversion
TheChoked class automatically converts rate limit strings to bucket parameters:
Dual Bucket Coordination
Both implementations coordinate request and token buckets:Error Handling
Both implementations handle errors gracefully:- Network failures: Automatic retry with exponential backoff
- Redis connection issues: Connection pooling and retry logic
- Service unavailability: Graceful degradation (may allow requests through)
- Invalid parameters: Immediate validation errors
Performance Characteristics
RedisTokenBucket Performance
- Latency: ~1-2ms per acquire() call (local Redis)
- Throughput: 10,000+ operations/second per bucket
- Memory: ~100 bytes per bucket in Redis
- Network: 1 round-trip per acquire() call
- Scalability: Horizontal scaling via Redis clustering
ProxyTokenBucket Performance
- Latency: ~10-50ms per acquire() call (network dependent)
- Throughput: 1,000+ operations/second per bucket
- Memory: Zero local memory usage
- Network: 1 HTTP request per acquire() call
- Scalability: Managed by proxy service infrastructure
Performance Optimization
- Both implementations cache connection objects
- Redis implementation uses connection pooling
- Proxy implementation reuses HTTP connections
- No performance penalty for unused buckets (request_capacity=0 or token_capacity=0)
Advanced Usage
Direct Instantiation (Not Recommended)
While possible, direct instantiation bypasses theChoked class conveniences:
Custom Integration
For custom rate limiting logic:Monitoring and Observability
Both implementations support monitoring:Thread Safety
- Both implementations are fully thread-safe and async-safe
- Redis implementation uses atomic Lua scripts
- Proxy implementation uses thread-safe HTTP clients
- Safe for concurrent use across multiple threads/processes
- No race conditions in bucket state management