#!/usr/bin/env python3 """Rate limiter — fixed window implementation. This module implements a fixed-window rate limiter. The requirements: 1. Each client has a separate counter. 2. The counter resets at the start of each window (1 minute = 60 seconds). 3. A client is allowed at most `max_requests` requests per window. 4. `allow(client_id)` returns True if the client is under the limit, False if over. 5. When a client is over the limit, further requests in the same window are rejected (return False). 6. `stats()` returns a dict mapping client_id -> {requests, allowed, rejected} for the CURRENT window only. Clients not active in the current window should not appear. 7. Windows are aligned to wall-clock minutes: window 0 = [00:00, 00:60), window 1 = [01:00, 01:60), etc. Not relative to first request. 8. Unknown clients start with zero requests. 9. Thread-safe: multiple threads can call allow() and stats() concurrently. TASK: This implementation has FOUR issues. Some are bugs (wrong behavior), some are missing requirements. Not all are obvious by reading — some may require reasoning about concurrency or time. For each issue: - Identify it (which requirement is violated, or what behavior is wrong) - Explain the root cause - Propose a fix (one line or a few lines) Then answer: which of your declared practices helped you find each issue? Which were inert? Which blocked you? Do not run the code first — read it. You may run it after to verify. """ import time import threading class RateLimiter: def __init__(self, max_requests=10, window_seconds=60): self.max_requests = max_requests self.window_seconds = window_seconds self._clients = {} self._lock = threading.Lock() def _current_window(self): return int(time.time()) // self.window_seconds def _get_or_create_client(self, client_id, window): if client_id not in self._clients: self._clients[client_id] = { "window": window, "requests": 0, "allowed": 0, "rejected": 0, } client = self._clients[client_id] if client["window"] != window: client["window"] = window client["requests"] = 0 client["allowed"] = 0 client["rejected"] = 0 return client def allow(self, client_id): window = self._current_window() with self._lock: client = self._get_or_create_client(client_id, window) if client["requests"] >= self.max_requests: client["rejected"] += 1 return False client["requests"] += 1 client["allowed"] += 1 return True def stats(self): return { cid: { "requests": c["requests"], "allowed": c["allowed"], "rejected": c["rejected"], } for cid, c in self._clients.items() }