How to implement rate limiting in Python
Build a simple sliding-window rate limiter in Python that enforces a max number of calls per time period and formats data with timestamps.
Python code
48 linesimport time
class RateLimiter:
def __init__(self, max_calls, period):
self.max_calls = max_calls
self.period = period
self.calls = []
def allow(self):
now = time.time()
# Remove calls older than the period window
self.calls = [t for t in self.calls if now - t < self.period]
if len(self.calls) < self.max_calls:
self.calls.append(now)
return True
return False
def wait_time(self):
if self.allow():
return 0
now = time.time()
self.calls = [t for t in self.calls if now - t < self.period]
if not self.calls:
return 0
return round(self.period - (now - min(self.calls)), 2)
def format_data(data, limiter):
"""
Format a list of items with a timestamp,
respecting the rate limit.
"""
results = []
for item in data:
if limiter.allow():
results.append(f"[{time.strftime('%H:%M:%S')}] {item}")
else:
results.append(f"[Rate limited] {item} (wait {limiter.wait_time()}s)")
return "\n".join(results)
if __name__ == "__main__":
# Allow 3 calls per 5-second window
limiter = RateLimiter(max_calls=3, period=5)
sample_data = ["apple", "banana", "cherry", "date", "elderberry", "fig"]
output = format_data(sample_data, limiter)
print(output)
Output
[10:15:30] apple
[10:15:30] banana
[10:15:30] cherry
[Rate limited] date (wait 4.5s)
[Rate limited] elderberry (wait 4.5s)
[Rate limited] fig (wait 4.5s)
How it works
The RateLimiter tracks timestamps of allowed calls in a list. The allow method filters out timestamps older than the period, then checks if the remaining count is below the maximum. When over the limit, wait_time calculates how long until the oldest call in the window expires. The format_data function applies this limiter to each item, appending a rate-limited message with the wait time when blocked. This sliding-window approach is simple and works well for single-process applications.
Common mistakes
- Calling wait_time() twice (it calls allow() internally, which adds a new call)
- Assuming thread safety when multiple threads share one limiter
- Forgetting that time.time() measures wall-clock time, not process time
Variations
- Use a fixed-window counter instead of sliding window for simpler logic
- Implement with collections.deque for O(1) pops from the front
Real-world use cases
- Throttling API client requests to respect third-party rate limits.
- Limiting login attempts or verification code requests per user window.
- Controlling batch job execution frequency in a background scheduler.
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.