Rate Limiting in Python with a Sliding Window
A beginner-friendly dataclass-based sliding window rate limiter that controls how many calls are allowed per time window.
Python code
32 linesimport time
from dataclasses import dataclass
@dataclass
class RateLimiter:
max_calls: int
window_seconds: float = 1.0
def __post_init__(self):
self.calls = []
self._start = time.monotonic()
def _update(self, now):
self.calls = [t for t in self.calls if now - t < self.window_seconds]
def allow(self):
now = time.monotonic()
self._update(now)
if len(self.calls) < self.max_calls:
self.calls.append(now)
return True
return False
if __name__ == "__main__":
limiter = RateLimiter(max_calls=3, window_seconds=0.5)
for i in range(6):
allowed = limiter.allow()
print(f"Request {i+1}: {'allowed' if allowed else 'blocked'}")
time.sleep(0.1)
Output
Request 1: allowed
Request 2: allowed
Request 3: allowed
Request 4: blocked
Request 5: allowed
Request 6: allowed
How it works
The RateLimiter uses a list of timestamps to track recent calls. Each allow() call records the current monotonic time and removes timestamps older than the window. If the number of stored timestamps is below the limit, the call is allowed and timestamp is added; otherwise it returns False to block. The sliding window updates lazily only when a new call arrives, which keeps overhead low. Using time.monotonic() avoids issues like system clock changes. This pattern is simple and easy to reason about, perfect for learning rate limiting fundamentals.
Common mistakes
- Using `time.time()` instead of `time.monotonic()`, leading to wrong windows if the clock changes.
- Forgetting to prune old timestamps, so the list grows indefinitely and blocks all future calls.
- Not checking if `max_calls` is non‑negative, which causes unexpected behavior.
- Hard‑coding sleep values in production instead of respecting the limiter's decisions.
Variations
- Use a `collections.deque` with `maxlen=max_calls` to keep only the most recent timestamps.
- Implement a fixed‑window limiter that resets a counter every `window_seconds`.
Real-world use cases
- Limiting API calls from a background worker to stay within a provider's quota.
- Throttling user‑triggered actions like sending SMS or password reset emails.
- Protecting a microservice endpoint from burst traffic in a demo or small service.
Sponsored
More from Reliability & rate limiting
- At Least Once with Idempotent Consumer in Python medium
- Build a Rate Limiter Decorator in Python easy
- Build a queue-based admission control system in Python easy
- Chaos Inject Random Failures in Python easy
- Circuit breaker failure threshold count in Python medium
- Exactly Once Processing Dedupe Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.