Limiting requests with the async and request modules
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When you call an API from Node.js, there are two limits you usually need to enforce at the same time: how many requests can run in parallel, and how many requests you send per second or minute. The old request package still appears in legacy services, and it is often paired with async utilities such as eachLimit and queue. Even if your team later migrates to fetch or axios, the same control patterns still apply.
The practical goal is predictable throughput without bursts that trigger 429 errors, socket exhaustion, or unstable latency. This guide focuses on reliable request limiting with async + request, including concurrency control, rate shaping, retries, and metrics. The examples are designed for production usage, where request outcomes are mixed and external APIs may throttle aggressively.
Core Sections
1) Model concurrency and rate separately
Concurrency and rate are related but different. A concurrency limit controls in-flight work. A rate limit controls launch frequency. If you enforce only concurrency, your process can still burst traffic at the start of each batch. If you enforce only rate, long-running requests can pile up and consume memory.
A useful starting point is:
maxInFlight: based on CPU, memory, and downstream connection limits.requestsPerSecond: based on provider documentation and observed 429s.retryBudget: maximum retries per item so failures do not stall the queue.
2) Limit in-flight calls with async.eachLimit
Use eachLimit to cap parallel calls while still processing a large input list.
This protects your process from opening too many sockets, but it does not guarantee a requests-per-second ceiling.
3) Add request-per-second shaping with async.queue
Pair a queue with a token refill interval to smooth request start times.
This design prevents sharp launch bursts. It also keeps rate control in one place so later migration away from request is straightforward.
4) Retries, backoff, and observability
Retries should be selective. Retry on transient network errors and 5xx statuses, but not on 4xx validation errors. Add jitter so many workers do not retry at exactly the same millisecond.
Track these metrics during rollout: success rate, p95 latency, queue depth, retry count, and 429 count. If 429 rises while queue depth is stable, reduce RPS. If queue depth keeps growing but 429 is near zero, raise concurrency carefully.
Common Pitfalls
- Using
Promise.allon a large list and accidentally launching thousands of requests at once. - Treating concurrency limit as a full rate limiter, then getting periodic bursts and 429 responses.
- Retrying all non-200 responses, including permanent 4xx errors that should fail fast.
- Ignoring timeout settings and allowing slow upstream calls to block queue slots indefinitely.
- Migrating from
requestwithout keeping equivalent backpressure and observability controls.
Summary
async and request can still provide stable request limiting in legacy Node.js services when you separate concurrency from rate, add bounded retries, and monitor live behavior. Start with conservative limits, then tune using production metrics rather than guesswork. If your team later adopts modern HTTP clients, keep the same architecture: queue-based backpressure, explicit throttle logic, and targeted retry policy. Those principles, not the client library, are what keep high-volume integrations reliable.
Related reading
- LinkedBlockingQueue vs ConcurrentLinkedQueue
- Linking Cancellation Tokens
- List of evented / asynchronous languages
- Load javascript async, then check DOM loaded before executing callback
- Linguistic meaning of 'let' variable in programming
- Linked list vs Array in Javascript
- Load jQuery Mobile script asynchronously?
- Load XDocument asynchronously
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.