Skip to main content

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
The appropriate implementation is automatically selected based on your Choked class configuration. You typically don’t need to use these classes directly.

RedisTokenBucket

Used when a Choked instance is created with redis_url. Provides distributed coordination using Redis with atomic Lua scripts.

Constructor

str
required
Unique identifier for the rate limit bucket
int
required
Maximum number of request tokens in the bucket (0 = no request limiting)
float
required
Rate at which request tokens are added to the bucket (tokens per second, 0.0 = no request limiting)
int
required
Maximum number of content tokens in the bucket (0 = no token limiting)
float
required
Rate at which content tokens are added to the bucket (tokens per second, 0.0 = no token limiting)
str
Redis connection URL. If not provided, uses the redis_url from the parent Choked instance.

Methods

acquire()

Attempts to acquire the specified number of request and content tokens from their respective buckets. Parameters:
  • requests_needed (int): Number of request tokens to acquire (typically 1)
  • tokens_needed (int): Number of content tokens to acquire (estimated from function args)
Returns: 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 parent Choked 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 a Choked instance is created with api_token. Provides managed rate limiting through the Choked proxy service.

Constructor

str
required
API token for the Choked proxy service
str
required
Unique identifier for the rate limit bucket
int
required
Maximum number of request tokens in the bucket (0 = no request limiting)
float
required
Rate at which request tokens are added to the bucket (tokens per second, 0.0 = no request limiting)
int
required
Maximum number of content tokens in the bucket (0 = no token limiting)
float
required
Rate at which content tokens are added to the bucket (tokens per second, 0.0 = no token limiting)

Methods

acquire()

Attempts to acquire tokens via the proxy service. Parameters:
  • requests_needed (int): Number of request tokens to acquire
  • tokens_needed (int): Number of content tokens to acquire
Returns: 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 the Choked decorator:

Rate Limit Conversion

The Choked 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

While possible, direct instantiation bypasses the Choked 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

Migration Between Backends

Switching between Redis and proxy backends:
The token bucket implementations provide the foundation for Choked’s powerful dual rate limiting system, handling the complex coordination between request and token limits while maintaining high performance and reliability.