JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 87
  • Score
    100M100P100Q75717F
  • License MIT

Generic ratelimit tool on top of ioredis.

Package Exports

  • ioredis-ratelimit
  • ioredis-ratelimit/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ioredis-ratelimit) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

ioredis-ratelimit

Generic rate limiter on top of ioredis.

Supports

  • Minimal difference between requests.
  • Batch actions.
  • Three levels of gratuitousness towards capped attempts.

Install

$ npm i ioredis-ratelimit --save

Usage

var ratelimit = require('ioredis-ratelimit')(options);

ratelimit().then(...).catch(...); // when key is string
ratelimit(id).then(...).catch(...); // when key is function
ratelimit(id, numActions).then(...).catch(...); // when key is function and batch actions are requested
ratelimit(numActions).then(...).catch(...); // when key is string

ratelimit.get().then(...); // return current size

Options

  • client: {Object} client of ioredis.
  • limit: {Number} max amount of calls in duration, default 1.
  • duration: {Number} duration in millisecond, default 1000.
  • difference: {Number} duration between each operation in millisecond, default 0.
  • key: {String|Function} ratelimiter's key.
  • mode: {String} binary, nary, and uniform, default binary.
  • error: {Error} throw when reach limit.

Examples

simple:

var Redis = require('ioredis');
var ratelimit = require('ioredis-ratelimit')({
  client: new Redis(),
  key: 'limiter',
  limit: 3,
  duration: 1000,
  difference: 0, // allow no interval between requests
});

ratelimit().then(console.log).catch(console.error); // { total: 3, remaining: 2 }
ratelimit().then(console.log).catch(console.error); // { total: 3, remaining: 1 }
ratelimit().then(console.log).catch(console.error); // { total: 3, remaining: 0 }
ratelimit().then(console.log).catch(console.error); // 429 - [Error: Exceeded the limit]

ratelimit.get().then(console.log) // { total: 3, remaining: 0, retryAfterMS: 1000 }

Express:

'use strict';

var app = require('express')();
var Redis = require('ioredis');
var ratelimit = require('ioredis-ratelimit')({
  client: new Redis(),
  key: function (req) {
    return 'limiter:' + req.user._id;
  },

  // 10 requests are allowed in 1s
  limit: 10,
  duration: 1000,

  // there should be at least 10ms interval between requests 
  difference: 10,
});

// ...

app.use(function (req, res, next) {
  ratelimit(req)
    .then(function () {
      next();
    })
    .catch(next);
});

app.get('/', function () {});

// ...

Batch actions

Binary

Binary mode is as straightforward as any other rate limiter.

var ratelimit = require('ioredis-ratelimit')({
  client: new Redis(),
  key: 'limiter',
  limit: 5,
  duration: 3000,
  mode: 'binary',
  error: new Error('Exceeded the limit')
});

ratelimit(2).then(console.log).catch(console.error); // { total: 2, acknowledged: 2, remaining: 3 }
ratelimit(2).then(console.log).catch(console.error); // { total: 4, acknowledged: 2, remaining: 1 }
ratelimit(2).then(console.log).catch(console.error); // 429 - [Error: Exceeded the limit]

N-ary

N-ary mode will try the best to fill up the bucket where partial saves are possible.

var ratelimit = require('ioredis-ratelimit')({
  client: new Redis(),
  key: 'limiter',
  limit: 5,
  duration: 3000,
  mode: 'nary',
  error: new Error('Exceeded the limit')
});

ratelimit(2).then(console.log).catch(console.error); // { total: 2, acknowledged: 2, remaining: 3 }
ratelimit(2).then(console.log).catch(console.error); // { total: 4, acknowledged: 2, remaining: 1 }
ratelimit(2).then(console.log).catch(console.error); // { total: 5, acknowledged: 1, remaining: 0 }
ratelimit(2).then(console.log).catch(console.error); // 429 - [Error: Exceeded the limit]

Uniform

Uniform mode will save all attempts when there's at least one slot.

var ratelimit = require('ioredis-ratelimit')({
  client: new Redis(),
  key: 'limiter',
  limit: 5,
  duration: 3000,
  mode: 'uniform',
  error: new Error('Exceeded the limit')
});

ratelimit(2).then(console.log).catch(console.error); // { total: 2, acknowledged: 2, remaining: 3 }
ratelimit(2).then(console.log).catch(console.error); // { total: 4, acknowledged: 2, remaining: 1 }
ratelimit(2).then(console.log).catch(console.error); // { total: 6, acknowledged: 2, remaining: 0 }
ratelimit(2).then(console.log).catch(console.error); // 429 - [Error: Exceeded the limit]

Test

$ npm test

License

MIT