Socket
Socket
Sign inDemoInstall

rate-limiter-flexible

Package Overview
Dependencies
Maintainers
1
Versions
163
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rate-limiter-flexible - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

lib/component/MemoryStorage/index.js

8

index.js

@@ -1,3 +0,7 @@

const RateLimiter = require('./lib/RateLimiter');
const RateLimiterRedis = require('./lib/RateLimiterRedis');
const RateLimiterMemory = require('./lib/RateLimiterMemory');
module.exports.RateLimiter = RateLimiter;
module.exports = {
RateLimiterRedis,
RateLimiterMemory
};
module.exports = class RateLimiterRes {
constructor() {
this._msBeforeNext = 0; // Milliseconds before next action
this._remainingPoints = 0; // Remaining points in current duration
constructor(remainingPoints, msBeforeNext) {
this.remainingPoints = typeof remainingPoints === 'undefined' ? 0 : remainingPoints ; // Remaining points in current duration
this.msBeforeNext = typeof msBeforeNext === 'undefined' ? 0 : msBeforeNext ; // Milliseconds before next action
}

@@ -6,0 +6,0 @@

{
"name": "rate-limiter-flexible",
"version": "0.2.0",
"version": "0.3.0",
"description": "Flexible API rate limiter backed by Redis for distributed node.js applications",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -6,5 +6,49 @@ [![Build Status](https://travis-ci.org/animir/node-rate-limiter-flexible.png)](https://travis-ci.org/animir/node-rate-limiter-flexible)

Flexible rate limiter with Redis as broker allows to control requests rate in cluster or distributed environment.
Backed on native Promises. It uses fixed window to limit requests.
Flexible rate limiter with Redis as broker allows to control requests rate in cluster or distributed environment.
It uses fixed window to limit requests.
Advantages:
* backed on native Promises
* actions can be done evenly over duration window to cut off picks
* no race conditions
* covered by tests
* no prod dependencies
* Redis errors don't result to broken app if `inMemoryLimiter` set up
* useful `penalty` and `reward` methods to change limits on some results of an action
### Benchmark
By `bombardier -c 1000 -l -d 10s -r 2500 -t 5s http://127.0.0.1:3000/pricing`
```text
Statistics Avg Stdev Max
Reqs/sec 2491.79 801.92 9497.25
Latency 8.62ms 11.69ms 177.96ms
Latency Distribution
50% 5.41ms
75% 7.65ms
90% 15.07ms
95% 27.24ms
99% 70.85ms
HTTP codes:
1xx - 0, 2xx - 25025, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
```
Endpoint is simple Express 4.x route launched in `node:latest` and `redis:alpine` Docker containers by PM2 with 4 workers
Endpoint is limited by `RateLimiterRedis` with config:
```javascript
new RateLimiterRedis(
{
redis: redisClient,
points: 1000,
duration: 1,
},
);
```
## Installation

@@ -16,2 +60,4 @@

### RateLimiterRedis
Redis client must be created with offline queue switched off

@@ -21,3 +67,3 @@

const redis = require('redis');
const { RateLimiter } = require('rate-limiter-flexible');
const { RateLimiterRedis, RateLimiterMemory } = require('rate-limiter-flexible');

@@ -32,9 +78,17 @@ const redisClient = redis.createClient({ enable_offline_queue: false });

const opts = {
redis: redisClient,
points: 5, // Number of points
duration: 5, // Per second(s)
execEvenly: false,
inMemoryLimiter: new RateLimiterMemory( // It will be used only on Redis error as insurance
{
points: 1, // 1 is fair if you have 5 workers and 1 cluster
duration: 5,
execEvenly: false,
})
};
const rateLimiter = new RateLimiter(redisClient, opts);
const rateLimiterRedis = new RateLimiterRedis(opts);
rateLimiter.consume(remoteAddress)
rateLimiterRedis.consume(remoteAddress)
.then(() => {

@@ -44,5 +98,5 @@ // ... Some app logic here ...

// Depending on results it allows to fine
rateLimiter.penalty(remoteAddress, 3);
rateLimiterRedis.penalty(remoteAddress, 3);
// or rise number of points for current duration
rateLimiter.reward(remoteAddress, 2);
rateLimiterRedis.reward(remoteAddress, 2);
})

@@ -52,6 +106,7 @@ .catch((rejRes) => {

// Some Redis error
// Decide what to do with it on your own
// Never happen if `inMemoryLimiter` set up
// Decide what to do with it in other case
} else {
// Can't consume
// If there is no error, rateLimiter promise rejected with number of ms before next request allowed
// If there is no error, rateLimiterRedis promise rejected with number of ms before next request allowed
const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;

@@ -64,7 +119,24 @@ res.set('Retry-After', String(secs));

### RateLimiterMemory
It manages limits in **current process memory**, so keep it in mind when use it in cluster
```javascript
const rateLimiter = new RateLimiterMemory( // It will be used only on Redis error as insurance
{
points: 1, // 1 is fair if you have 5 workers and 1 cluster
duration: 5,
execEvenly: false,
});
// Usage is the same as for RateLimiterRedis
// Except: it never rejects Promise with Error
```
## Options
* `points` Maximum number of points can be consumed over duration
* `duration` Number of seconds before points are reset
* `execEvenly` Delay action to be executed evenly over duration
* `points` `Default: 4` Maximum number of points can be consumed over duration
* `duration` `Default: 1` Number of seconds before points are reset
* `execEvenly` `Default: false` Delay action to be executed evenly over duration
First action in duration is executed without delay.

@@ -74,3 +146,9 @@ All next allowed actions in current duration are delayed by formula `msBeforeDurationEnd / (remainingPoints + 2)`

Note: it isn't recommended to use it for long duration, as it may delay action for too long
* `inMemoryLimiter` `Default: undefined` RateLimiterMemory object to store limits in process memory, when Redis comes up with any error.
Be careful when use it in cluster or in distributed app.
It may result to floating number of allowed actions.
If an action with a same `key` is launched on one worker several times in sequence, limiter will reach out of points soon.
Omit it if you want strictly use Redis and deal with errors from it
## API

@@ -93,3 +171,3 @@

* resolved when point(s) is consumed, so action can be done
* rejected when some Redis error happened, where reject reason `rejRes` is Error object
* only for RateLimiterRedis: rejected when some Redis error happened, where reject reason `rejRes` is Error object
* rejected when there is no points to be consumed, where reject reason `rejRes` is `RateLimiterRes` object

@@ -103,14 +181,14 @@

Fine `key` by `points` number of points.
Fine `key` by `points` number of points for **one duration**.
Note: Depending on time penalty may go to next durations
Doesn't return anything
Returns Promise
### rateLimiter.reward(key, points = 1)
Reward `key` by `points` number of points.
Reward `key` by `points` number of points for **one duration**.
Note: Depending on time reward may go to next durations
Doesn't return anything
Returns Promise

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc