How to Mock and Test a Rate-Limited Source Stream in Python
Build a class that rate-limits emitted items using a sliding window and test it with a simulated stream in Python.
Python code
28 linesimport time
from collections import deque
class RateLimitedSource:
def __init__(self, max_rate, window=1.0):
self.max_rate = max_rate
self.window = window
self._timestamps = deque()
def emit(self, item):
now = time.monotonic()
while self._timestamps and self._timestamps[0] <= now - self.window:
self._timestamps.popleft()
if len(self._timestamps) < self.max_rate:
self._timestamps.append(now)
return item
raise RuntimeError("Rate limit exceeded")
if __name__ == "__main__":
source = RateLimitedSource(max_rate=3, window=1.0)
for i in range(5):
try:
print(source.emit(f"item-{i}"))
except RuntimeError:
print(f"item-{i} rejected")
time.sleep(0.5)
Output
item-0
item-1
item-2
item-3 rejected
item-4 rejected
How it works
The RateLimitedSource class uses time.monotonic() and a deque to track timestamps within a sliding window. Each emit call first removes timestamps older than the window, then checks if the count is below the max rate before allowing the item. When the limit is exceeded, a RuntimeError is raised, which the test loop catches to simulate a rejected event. This pattern mimics how streaming pipelines throttle data intake to prevent overload. The mock stream in __main__ demonstrates graceful handling of rejections by sleeping briefly before retrying.
Common mistakes
- Using `time.time()` instead of `time.monotonic()` allows system clock changes to skew rate calculations
- Forgetting to evict old timestamps before checking the count leads to inaccurate throttling
- Letting the deque grow unbounded in production without periodic cleanup causes memory bloat
Variations
- Use a token bucket algorithm instead of a sliding window for burst handling
- Replace RuntimeError with a custom RateLimitExceeded exception for cleaner error handling
Real-world use cases
- Mocking upstream API rate limits when building a Kafka producer that fetches from a restricted REST service.
- Simulating throttled data sources in unit tests for Spark streaming ingestion jobs.
- Validating backpressure logic in a data pipeline that consumes from a rate-limited partner feed.
Sponsored
More from Big data & Spark
Keep learning
Related tutorials and quizzes for this topic.