Answer A: Google Gemini 2.5 Pro
import time import threading import random from collections import deque from dataclasses import dataclass, field from typing import List, Tuple, Dict, Optional @dataclass class ClientState: """Holds all state for a single client.""" lock: threading.Lock = field(default_factory=threading.Lock, repr=False) requests: deque[Tuple[float, int]] = field(default_factory=deque) burst: int = 0 stats: Dict[str, int] = field(default_factory=lambda: {"admitted": 0, "rejected": 0, "revoked": 0}) revoked_log: List[Tuple[float, int]] = field(default_factory=list) class RateLimiter: """ A thread...
Show Full Answer ▼
import time import threading import random from collections import deque from dataclasses import dataclass, field from typing import List, Tuple, Dict, Optional @dataclass class ClientState: """Holds all state for a single client.""" lock: threading.Lock = field(default_factory=threading.Lock, repr=False) requests: deque[Tuple[float, int]] = field(default_factory=deque) burst: int = 0 stats: Dict[str, int] = field(default_factory=lambda: {"admitted": 0, "rejected": 0, "revoked": 0}) revoked_log: List[Tuple[float, int]] = field(default_factory=list) class RateLimiter: """ A thread-safe rate limiter implementing a sliding window algorithm with priority queues and burst allowances. """ def __init__(self, max_requests: int, window_seconds: float, default_burst: int = 0): if max_requests <= 0 or window_seconds <= 0: raise ValueError("max_requests and window_seconds must be positive.") self.max_requests = max_requests self.window_seconds = window_seconds self.default_burst = default_burst self._clients: Dict[str, ClientState] = {} self._clients_lock = threading.Lock() def _get_or_create_client(self, client_id: str) -> ClientState: """Atomically get or create a client's state object.""" if client_id not in self._clients: with self._clients_lock: # Double-check locking pattern to avoid race conditions on creation if client_id not in self._clients: self._clients[client_id] = ClientState(burst=self.default_burst) return self._clients[client_id] def set_client_burst(self, client_id: str, burst: int) -> None: """Override burst allowance for a specific client.""" client = self._get_or_create_client(client_id) with client.lock: client.burst = burst def allow(self, client_id: str, priority: int = 3, timestamp: Optional[float] = None) -> bool: """ Check if a request is allowed. If timestamp is None, use current time. Returns True if the request is admitted, False if rejected. """ if not 1 <= priority <= 5: raise ValueError("Priority must be an integer between 1 and 5.") now = timestamp if timestamp is not None else time.time() client = self._get_or_create_client(client_id) with client.lock: # 1. Slide the window: remove expired requests window_start = now - self.window_seconds while client.requests and client.requests[0][0] < window_start: client.requests.popleft() # 2. Determine the effective request limit (base + burst) effective_max = self.max_requests if client.burst > 0 and client.requests: first_req_time = client.requests[0][0] if (now - first_req_time) >= (self.window_seconds / 2.0): effective_max += client.burst current_requests_count = len(client.requests) # 3. Decision: Admit, Revoke, or Reject if current_requests_count < effective_max: # Case A: Space is available (either base or burst) client.requests.append((now, priority)) client.stats['admitted'] += 1 return True else: # Case B: Window is full, check for priority revocation # Find the request with the highest priority number (lowest actual priority) worst_request_idx = -1 worst_priority = -1 for i, req in enumerate(client.requests): if req[1] > worst_priority: worst_priority = req[1] worst_request_idx = i # If a suitable candidate for revocation exists... if worst_request_idx != -1 and worst_priority > priority: # Revoke the lowest-priority request revoked_req = client.requests[worst_request_idx] del client.requests[worst_request_idx] client.revoked_log.append(revoked_req) client.stats['revoked'] += 1 # Admit the new, higher-priority request client.requests.append((now, priority)) client.stats['admitted'] += 1 return True else: # Case C: No space and no possible revocation -> Reject client.stats['rejected'] += 1 return False def get_stats(self, client_id: str) -> dict: """ Return a dict with keys: 'admitted', 'rejected', 'revoked', 'utilization' """ if client_id not in self._clients: return {'admitted': 0, 'rejected': 0, 'revoked': 0, 'utilization': 0.0} client = self._clients[client_id] with client.lock: # Slide window for accurate utilization calculation at the current time now = time.time() window_start = now - self.window_seconds while client.requests and client.requests[0][0] < window_start: client.requests.popleft() current_count = len(client.requests) utilization = min(1.0, current_count / self.max_requests) if self.max_requests > 0 else 0.0 stats_copy = client.stats.copy() stats_copy['utilization'] = utilization return stats_copy def get_revoked_log(self, client_id: str) -> list: """ Return a list of (timestamp, priority) tuples for revoked requests for the given client, in chronological order. """ if client_id not in self._clients: return [] client = self._clients[client_id] with client.lock: # The log is already in chronological order of revocation return list(client.revoked_log) # --- Demonstration Script --- def run_demonstration(): print("--- Rate Limiter Demonstration ---") limiter = RateLimiter(max_requests=5, window_seconds=10.0, default_burst=2) # --- Client 1: Standard, Rejection, and Priority Revocation --- client1 = "client-A" print(f"\n--- Testing Client: {client1} ---") # 1. Fill the window with medium-priority requests print("1. Filling the window (5 requests)...") for i in range(5): limiter.allow(client1, priority=4, timestamp=float(i)) # 2. Reject a request print("2. Sending a 6th request (should be rejected)...") is_allowed = limiter.allow(client1, priority=4, timestamp=5.0) print(f" Request at T=5.0 allowed: {is_allowed} (Expected: False)") # 3. Revoke a low-priority request with a high-priority one print("3. Sending a high-priority request (should revoke one)...") is_allowed = limiter.allow(client1, priority=1, timestamp=6.0) print(f" High-priority request at T=6.0 allowed: {is_allowed} (Expected: True)") # 4. Let the window slide print("4. Waiting for window to slide...") # At T=11.0, request at T=0.0 has expired. Window contains T=1,2,3,4,6 (5 requests) is_allowed = limiter.allow(client1, priority=5, timestamp=11.0) print(f" Request at T=11.0 allowed: {is_allowed} (Expected: False)") # At T=12.0, requests at T=0,1 have expired. Window contains T=2,3,4,6 (4 requests) is_allowed = limiter.allow(client1, priority=5, timestamp=12.0) print(f" Request at T=12.0 allowed: {is_allowed} (Expected: True)") # --- Client 2: Burst Allowance --- client2 = "client-B" print(f"\n--- Testing Client: {client2} (Burst) ---") limiter.set_client_burst(client2, 3) # Override burst to 3 for this client # 1. Send initial request print("1. Sending initial request at T=20.0...") limiter.allow(client2, priority=3, timestamp=20.0) # 2. Try to burst before half-window (should fail) print("2. Attempting to burst before half-window (T=24.0)...") # Window is 10s, half is 5s. T=24.0 is 4s after T=20.0. # Should allow up to max_requests (5) for i in range(4): # Requests 2, 3, 4, 5 limiter.allow(client2, priority=3, timestamp=24.0) is_allowed = limiter.allow(client2, priority=3, timestamp=24.1) print(f" 6th request at T=24.1 (before burst active) allowed: {is_allowed} (Expected: False)") # 3. Activate burst after half-window print("3. Activating burst after half-window (T=25.0)...") # T=25.0 is 5s after T=20.0. Burst is now active. # Limit is now 5 (base) + 3 (burst) = 8. # Currently 5 requests in window (from T=20, T=24). Should allow 3 more. allowed_count = 0 for _ in range(4): # Try to send 4 more if limiter.allow(client2, priority=3, timestamp=25.0): allowed_count += 1 print(f" Allowed {allowed_count} burst requests at T=25.0. (Expected: 3)") # --- Final Stats --- print("\n--- Final Stats ---") print(f"Client A Stats: {limiter.get_stats(client1)}") print(f"Client A Revoked Log: {limiter.get_revoked_log(client1)}") print(f"Client B Stats: {limiter.get_stats(client2)}") print(f"Client B Revoked Log: {limiter.get_revoked_log(client2)}") print(f"Unknown Client Stats: {limiter.get_stats('client-C')}") # --- Multithreaded Test --- def run_multithreaded_test(): print("\n--- Multithreaded Test ---") limiter = RateLimiter(max_requests=20, window_seconds=5.0) client_id = "mt-client" num_threads = 5 requests_per_thread = 10 total_requests = num_threads * requests_per_thread barrier = threading.Barrier(num_threads) def worker(): barrier.wait() for i in range(requests_per_thread): priority = random.randint(1, 5) limiter.allow(client_id, priority=priority) time.sleep(0.01) threads = [threading.Thread(target=worker) for _ in range(num_threads)] for t in threads: t.start() for t in threads: t.join() print(f"\nFinished multithreaded test with {num_threads} threads and {requests_per_thread} requests each.") stats = limiter.get_stats(client_id) print(f"Final Stats for {client_id}: {stats}") total_processed = stats['admitted'] + stats['rejected'] print(f"Total requests attempted: {total_requests}") print(f"Total requests processed (admitted + rejected): {total_processed}") if total_processed == total_requests: print("Test PASSED: All requests were accounted for, indicating thread safety.") else: print(f"Test FAILED: Mismatch in request counts. Expected {total_requests}, got {total_processed}.") if __name__ == '__main__': run_demonstration() run_multithreaded_test()
Result
Winning Votes
1 / 3
Average Score
Total Score
Overall Comments
Answer A provides a very strong and correct implementation of the rate limiter. Its use of per-client locks ensures excellent concurrency, which is crucial for a rate limiter handling multiple clients simultaneously. The code is clean, well-structured, and effectively handles all specified features and edge cases, including a robust demonstration script. While it uses a linear scan for priority revocation instead of a heap, its overall correctness, clarity, and practical concurrency make it a superior solution.
View Score Details ▼
Correctness
Weight 35%The sliding window, priority revocation (linear scan), burst allowance, and statistics are all correctly implemented. The per-client locking ensures robust thread safety. Utilization is calculated against the base max_requests, which is a common interpretation.
Completeness
Weight 20%All required methods and features are fully implemented, and the demonstration script comprehensively exercises all aspects of the rate limiter.
Code Quality
Weight 20%The code is well-structured, uses dataclasses effectively, and has clear method names and comments. The granular per-client locking is a strong point for concurrency. The linear scan for revocation is a minor performance trade-off for simplicity.
Practical Value
Weight 15%The solution offers high practical value due to its robust thread safety model with per-client locks, allowing for high concurrency across different clients. This makes it suitable for real-world applications where multiple clients might hit the limiter simultaneously.
Instruction Following
Weight 10%All instructions, including the interface, features, demonstration script, and edge cases, are followed correctly. The only minor point is the use of a linear scan for priority revocation, whereas the prompt preferred a heap or sorted structure.
Total Score
Overall Comments
Answer A provides a runnable implementation with per-client locking, sliding-window eviction, priority-based replacement, burst support, stats, and a multithreaded demo. Its structure is readable and mostly correct, but it does not validate client IDs or burst values, uses a linear scan rather than a priority structure for revocation, and its window-boundary handling is incorrect for the stated edge case because it keeps requests exactly at the cutoff. Utilization is also capped against max_requests only, which ignores active burst capacity.
View Score Details ▼
Correctness
Weight 35%Core sliding-window admission, burst gating, and priority replacement generally work, and thread safety is reasonable via per-client locks. However, requests exactly at the window boundary are treated as still active because eviction uses < instead of <=, which conflicts with the stated edge-case requirement. Client ID and burst validation are also missing, and utilization ignores burst-adjusted capacity.
Completeness
Weight 20%Includes the full class interface, stats, revoked log, a sequential demonstration, and a multithreaded test. But some requested edge cases are not fully handled or demonstrated, especially invalid client IDs, exact boundary behavior, and explicit multiple revocations in sequence.
Code Quality
Weight 20%Readable and organized with a helpful dataclass and clear comments. However, the class docstring says priority queues even though revocation is a linear scan over a deque, some validation is absent, and the demo expectations are embedded informally rather than systematically tested.
Practical Value
Weight 15%Useful as a runnable example and easy to follow, but less production-ready because of incomplete validation, boundary mismatch, and naive revocation scanning. The multithreaded test checks accounting but is fairly lightweight.
Instruction Following
Weight 10%Follows most of the prompt and provides complete runnable code, stats, revoked logs, and concurrency. Still, it falls short on preferred data structure choice, boundary handling, and graceful handling of empty client IDs in queries.
Total Score
Overall Comments
Answer A provides a clean, readable implementation with a dataclass-based client state and per-client locking. The sliding window uses a deque with linear scan for priority revocation, which is correct but not optimal. The demonstration script exercises most features well. However, there are several correctness issues: (1) The sliding window eviction uses strict less-than (< window_start) rather than less-than-or-equal, meaning requests exactly at the boundary are not expired — this is a minor boundary handling issue. (2) The revoked request's slot counting is subtly wrong — when a request is revoked, it's removed from the deque but still counted in the admitted stats without being decremented, which is correct per the spec (revoked requests were admitted). (3) The utilization calculation in get_stats divides by max_requests rather than the effective capacity (base + burst), which could be debatable but doesn't match the burst-aware capacity. (4) The burst activation check uses >= for half-window which is correct. (5) The multithreaded test uses 5 threads instead of the requested minimum of 4, which is fine, but uses a single client which is less interesting than testing contention on shared clients. The per-client locking strategy is good for concurrency but the initial check outside the lock in _get_or_create_client has a potential issue (reading _clients dict without lock), though the double-check pattern mitigates this.
View Score Details ▼
Correctness
Weight 35%Answer A correctly implements the core sliding window and priority revocation logic. However, the boundary handling uses strict less-than for expiry (requests at exact boundary not expired), and utilization is calculated against max_requests rather than effective capacity. The linear scan for revocation is correct but not optimal. The burst activation logic is correct with >= half-window check.
Completeness
Weight 20%Answer A covers all five required features: sliding window, priority revocation, burst allowance, thread safety, and statistics. The demo exercises most features. However, the multithreaded test uses a single client rather than demonstrating contention on shared resources. Edge cases like unknown clients are handled. Priority validation raises ValueError as expected.
Code Quality
Weight 20%Answer A has excellent code organization with a clean dataclass for client state, clear method structure, and good comments. The per-client locking strategy is well-designed. Variable naming is clear and consistent. The demonstration script is well-organized with clear expected outputs.
Practical Value
Weight 15%Answer A provides a working rate limiter suitable for moderate use cases. The per-client locking is good for concurrency. However, the linear scan for revocation could be a bottleneck with many requests. The demonstration output is clear and educational. The implementation would work in production with some refinements.
Instruction Following
Weight 10%Answer A follows the interface specification correctly. It implements all required methods with correct signatures. The demo creates a limiter with the specified parameters and exercises most features. Uses 5 threads instead of the minimum 4 requested. Prints stats and revoked logs as required.