Design a rate-limited REST API data collection script

Tests client-side throttling discipline versus reactive 429 handling. Strong answers proactively pace calls using rate-limit headers, cap concurrency, and apply exponential backoff with jitter. Red flag: tight-loop retries or ignoring headers.
WHAT THIS TESTS: This question tests whether you design client-side systems that respect external constraints proactively rather than reacting to failures. Interviewers want to see that you understand backpressure, can prevent 429 storms, and know how to maximize throughput within a fixed quota without burning the API provider or your own reliability.
A GOOD ANSWER COVERS: First, proactive throttling before the server punishes you. You should mention pacing requests to stay safely under the 100 requests per minute limit using a token bucket or a fixed delay of at least 600 milliseconds between calls. Second, header awareness. Parse X-RateLimit-Remaining, X-RateLimit-Reset, or Retry-After to dynamically adjust sleep rather than guessing. Third, concurrency control. Use a bounded worker pool of three to five workers instead of unbounded threads or async tasks that create burst traffic. Fourth, resilient retries. Apply exponential backoff with full jitter when you do receive a 429, cap retries at three to five attempts, and fail gracefully if the limit persists. Fifth, efficiency optimizations. Maximize page size, cache responses where appropriate, and deduplicate requests so you do not waste quota on redundant data.
COMMON WRONG ANSWERS: The biggest red flag is suggesting a tight retry loop on 429 without backoff. Another is proposing unlimited parallel connections and hoping the server will throttle you. Arbitrary sleeps like time.sleep(1) without reading headers show a lack of systems thinking. Finally, ignoring pagination or batching and making one call per record wastes the limited budget.
LIKELY FOLLOW-UPS: The interviewer might ask how your design changes if the API returns 429s with no Retry-After header, or how you would distribute the collection across multiple nodes without violating the global limit. They may also probe how you would monitor and alert when you are approaching the threshold, or how to prioritize certain endpoints over others when quota is scarce.
ONE CONCRETE EXAMPLE: Suppose you need to fetch ten thousand user records. You configure a session with a semaphore limiting you to four concurrent workers. Before each batch, you check X-RateLimit-Remaining. If it drops below ten, you pause until the X-RateLimit-Reset timestamp. Each worker sleeps 650 milliseconds between requests by default. On a 429, the worker sleeps for 2 to the power of attempt seconds times a random jitter factor, up to three retries. If the queue backs up beyond a hundred items, you shed load by deferring non-critical metadata fetches. This keeps you at roughly ninety requests per minute, safely under the cap, while still using concurrency to hide network latency.
Source: lunar.dev
Read the original → lunar.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.