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.

Easy Python 3.9+ Aug 9, 2026 Reliability & rate limiting 13 views 0 copies

Python code

35 lines
Python 3.9+
from 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

stdout
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

  1. Use `time.monotonic()` instead of `time.time()` to avoid system clock changes.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Reliability & rate limiting

Related tutorials and quizzes for this topic.