natesilva / p-ratelimit

Promise-based utility to make sure you don’t call rate-limited APIs too quickly.
MIT License
65 stars 11 forks source link
concurrency distributed-systems promise rate-limiting redis

p-ratelimit npm license node

Makes sure you don’t call rate-limited APIs too quickly.

This is an easy-to-use utility for calling rate-limited APIs. It will prevent you from exceeding rate limits by queueing requests that would go over your rate limit quota.

Rate-limits can be applied across multiple servers if you use Redis.

It works with any API function that returns a Promise.

Install

$ npm i p-ratelimit

What’s different

Example

const { pRateLimit } = require('p-ratelimit');
// import { pRateLimit } from 'p-ratelimit';       // TypeScript

// create a rate limiter that allows up to 30 API calls per second,
// with max concurrency of 10
const limit = pRateLimit({
    interval: 1000,             // 1000 ms == 1 second
    rate: 30,                   // 30 API calls per interval
    concurrency: 10,            // no more than 10 running at once
    maxDelay: 2000              // an API call delayed > 2 sec is rejected
});

async function main() {
  // original WITHOUT rate limiter:
  result = await someFunction(42);
  // with rate limiter:
  result = await limit(() => someFunction(42));
}

main();

Configuration

The Quota configuration object passed to pRateLimit offers the following configuration settings:

If you care about rate limiting

Set both of these:

If you care about limiting concurrency

If you care about both rate limiting and concurrency

If you want both rate limiting and concurrency, use all three of the above settings (interval, rate, concurrency).

Other options

If you make an API request that would exceed rate limits, it’s queued and delayed until it can run within the rate limits. Setting maxDelay will cause the API request to fail if it’s delayed too long.

See the Using Redis section for a discussion of the fastStart option.

Distributed rate limits

See Using Redis for a detailed discussion.

You can use Redis to coordinate a rate limit among a pool of servers.

const { pRateLimit, RedisQuotaManager } = require('p-ratelimit');

// These must be the same across all servers that share this quota:
const channelName = 'my-api-family';
const quota = { rate: 100, interval: 1000, concurrency: 50 };

// Create a RedisQuotaManager
const qm = new RedisQuotaManager(
    quota,
    channelName,
    redisClient
);

// Create a rate limiter that uses the RedisQuotaManager
const limit = pRateLimit(qm);

// now use limit(…) as usual

Each server that registers with a given channelName will be allotted 1/(number of servers) of the available quota. For example, if the pool consists of four servers, each will receive 1/4 the available quota.

When a new server joins the pool, the quota is dynamically adjusted. If a server goes away, its quota is reallocated among the remaining servers within a few minutes.

License

MIT © Nate Silva