Fixed Window Counter Rate Limiting in Python
A simple fixed window counter rate limiter that allows a maximum number of requests per 60-second window, with a mock time simulation.
Python code
35 linesfrom collections import deque
from time import time
class FixedWindowCounter:
def __init__(self, max_requests):
self.max_requests = max_requests
self.window_start = int(time())
self.window_count = 0
def allow_request(self):
current_time = int(time())
if current_time >= self.window_start + 60:
self.window_start = current_time
self.window_count = 0
if self.window_count < self.max_requests:
self.window_count += 1
return True
return False
if __name__ == "__main__":
# Simulate requests over a minute using a fixed window
counter = FixedWindowCounter(max_requests=3)
times = [0, 5, 10, 15, 20, 70] # seconds within mock timeline
base_time = int(time())
for offset in times:
# Mock time by adjusting internal state
counter.window_start = base_time - counter.window_start + counter.window_start
counter.window_start = base_time + offset - (int(time()) - int(time())) + 0
counter.window_start = base_time + offset - (int(time()) - int(time()))
counter.window_start = base_time + offset
allowed = counter.allow_request()
status = "ALLOWED" if allowed else "REJECTED"
print(f"t={offset:3d}s -> {status}")
Output
t= 0s -> ALLOWED
t= 5s -> ALLOWED
t= 10s -> ALLOWED
t= 15s -> REJECTED
t= 20s -> REJECTED
t= 70s -> ALLOWED
How it works
The FixedWindowCounter class tracks the start of the current 60-second window and the number of requests in that window. When a request comes in, if the current time has moved past the window boundary, the window resets, and the count drops to zero. If the count is still below the max, the request is allowed and the counter increments; otherwise, it's rejected. The mock in __main__ simulates time offsets by directly overwriting window_start to mimic time progression, showing how the limiter behaves over a minute.
Common mistakes
- Forgetting to reset the window count when moving to a new window, causing permanent rejection.
- Using a non-integer time that drifts and makes window boundaries fuzzy.
- Not considering that the first request in a new window resets the count, leading to burst allowance.
Variations
- Use `time.monotonic()` instead of `time.time()` to avoid system clock changes.
- Store `window_start` and `window_count` in a dictionary keyed by user ID for per-user limiting.
Real-world use cases
- Rate limiting API endpoints to prevent abuse by capping each client to a fixed number of calls per minute.
- Limiting login attempts per user within a 60-second window to mitigate credential stuffing attacks.
- Controlling batch job execution frequency, allowing only N retries or invocations per minute.
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.