Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

rate-limiter-flexible

Package Overview
Dependencies
Maintainers
1
Versions
164
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.12.6 to 0.13.0

lib/RateLimiterMySQL.js

12

BLOCK_STRATEGY.md

@@ -1,4 +0,4 @@

## Block Strategy
## In-memory Block Strategy
Block strategy is against DDoS attacks.
In-memory Block Strategy is against DDoS attacks.
Redis is quite fast. It can process over 100k requests per second.

@@ -17,3 +17,3 @@ However, performance still depends on amount of requests per second.

Block strategy algorithm developed with specificity rate limiter in mind:
In-memory Block strategy algorithm developed with specificity rate limiter in mind:
* it doesn't use `setTimeout` to expire blocked keys, so doesn't overload Event Loop

@@ -59,3 +59,3 @@ * blocked keys expired in two cases:

#### Without Block Strategy
#### Without In-memory Block Strategy

@@ -89,3 +89,3 @@ 5 points per second to consume

#### Setup Block Strategy
#### Setup In-memory Block Strategy

@@ -125,3 +125,3 @@ 5 points per second to consume

* Latency is smaller with Block Strategy
* Latency is smaller with In-memory Block Strategy
* Number of requests to Redis less on 59k roughly
const RateLimiterAbstract = require('./RateLimiterAbstract');
const BlockedKeys = require('./component/BlockedKeys');
const RateLimiterRes = require('./RateLimiterRes');

@@ -24,8 +25,11 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {

getInmemoryBlockMsBeforeExpire(rlKey) {
if (this.inmemoryBlockOnConsumed > 0) {
return this._inmemoryBlockedKeys.msBeforeExpire(rlKey);
get client() {
return this._client;
}
set client(value) {
if (typeof value === 'undefined') {
throw new Error('storeClient is not set');
}
return 0;
this._client = value;
}

@@ -37,2 +41,4 @@

*
* It uses _getRateLimiterRes function to prepare RateLimiterRes from store result
*
* @param resolve

@@ -91,2 +97,10 @@ * @param reject

getInmemoryBlockMsBeforeExpire(rlKey) {
if (this.inmemoryBlockOnConsumed > 0) {
return this._inmemoryBlockedKeys.msBeforeExpire(rlKey);
}
return 0;
}
get inmemoryBlockOnConsumed() {

@@ -147,2 +161,53 @@ return this._inmemoryBlockOnConsumed;

/**
*
* @param key
* @param pointsToConsume
* @returns {Promise<any>}
*/
consume(key, pointsToConsume = 1) {
return new Promise((resolve, reject) => {
const rlKey = this.getKey(key);
const inmemoryBlockMsBeforeExpire = this.getInmemoryBlockMsBeforeExpire(rlKey);
if (inmemoryBlockMsBeforeExpire > 0) {
return reject(new RateLimiterRes(0, inmemoryBlockMsBeforeExpire));
}
this._upsert(rlKey, pointsToConsume, this.msDuration)
.then((res) => {
this._afterConsume(resolve, reject, rlKey, pointsToConsume, res);
})
.catch((err) => {
this._handleError(err, 'consume', resolve, reject, key, pointsToConsume);
});
});
}
penalty(key, points = 1) {
const rlKey = this.getKey(key);
return new Promise((resolve, reject) => {
this._upsert(rlKey, points, this.msDuration)
.then((res) => {
resolve(this._getRateLimiterRes(rlKey, points, res));
})
.catch((err) => {
this._handleError(err, 'penalty', resolve, reject, key, points);
});
});
}
reward(key, points = 1) {
const rlKey = this.getKey(key);
return new Promise((resolve, reject) => {
this._upsert(rlKey, -points, this.msDuration)
.then((res) => {
resolve(this._getRateLimiterRes(rlKey, -points, res));
})
.catch((err) => {
this._handleError(err, 'reward', resolve, reject, key, -points);
});
});
}
/**
* Get RateLimiterRes object filled depending on storeResult, which specific for exact store

@@ -164,3 +229,3 @@ *

* @param rlKey
* @param points
* @param initPoints
* @param msDuration

@@ -170,5 +235,13 @@ *

*/
_block(rlKey, points, msDuration) { // eslint-disable-line no-unused-vars
return Promise.reject(new Error("You have to implement the method '_block'!"));
_block(rlKey, initPoints, msDuration) {
return new Promise((resolve, reject) => {
this._upsert(rlKey, initPoints, msDuration, true)
.then(() => {
resolve(new RateLimiterRes(0, msDuration, initPoints));
})
.catch((err) => {
this._handleError(err, 'block', resolve, reject, this.parseKey(rlKey), initPoints);
});
});
}
};
## RateLimiterMongo
RateLimiterMongo creates unique collection for each rate limiter `keyPrefix`
### Benchmark

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

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

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

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

Flexible rate limiter and anti-DDoS protector works in process
_Memory_, _Cluster_, _MongoDB_ or _Redis_ allows to control requests rate in single process or distributed environment.
_Memory_, _Cluster_, _MongoDB_, _MySQL_ or _Redis_ allows to control requests rate in single process or distributed environment.

@@ -37,2 +37,3 @@ It uses **fixed window** as it is much faster than rolling window.

* [RateLimiterMongo](#ratelimitermongo)
* [RateLimiterMySQL](#ratelimitermysql)
* [RateLimiterCluster](#ratelimitercluster)

@@ -48,3 +49,6 @@ * [RateLimiterMemory](#ratelimitermemory)

Average latency of pure NodeJS endpoint limited by (all set up on one server):
Average latency during test pure NodeJS endpoint in cluster of 4 workers with everything set up on one server by
1000 concurrent clients with maximum 2000 requests per sec during 30 seconds.
```text

@@ -57,2 +61,7 @@ 1. Memory 0.34 ms

500 concurrent clients with maximum 1000 req per sec during 30 seconds
```text
5. MySQL 11.10 ms
```
#### RateLimiterRedis benchmark

@@ -127,3 +136,3 @@

insuranceLimiter: new RateLimiterMemory(
// It will be used only on Redis or Mongo error as insurance
// It will be used only on Redis, Mongo or MySQL error as insurance
// Can be any implemented limiter like RateLimiterMemory or RateLimiterRedis extended from RateLimiterAbstract

@@ -224,4 +233,37 @@ {

`insuranceLimiter` can be setup to avoid errors, but all changes won't be written from `insuranceLimiter` to `RateLimiterMongo` when connection established
`insuranceLimiter` can be setup to avoid errors, but all changes won't be written from `insuranceLimiter` to `RateLimiterMongo` when connection established
### RateLimiterMySQL
It supports `mysql2` and `mysql` node packages.
MySQL connection have to be created with allowed `multipleStatementes`.
Limits data, which expired more than an hour ago, are removed every 5 minutes by `setTimeout`.
[Read more about RateLimiterMySQL here](https://github.com/animir/node-rate-limiter-flexible/blob/master/MYSQL.md)
```javascript
const mysql = require('mysql2');
const client = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'secret',
multipleStatements: true // it is required by limiter
});
const opts = {
storeClient: client,
dbName: 'mydb',
tableName: 'mytable', // all limiters store data in one table
points: 5, // Number of points
duration: 1, // Per second(s)
};
const rateLimiter = new RateLimiterMySQL(opts);
// Usage is the same as for RateLimiterRedis
```
Connection to MySQL takes milliseconds, so any method of rate limiter is rejected with Error, until connection is established
### RateLimiterCluster

@@ -266,3 +308,3 @@

```javascript
const rateLimiter = new RateLimiterMemory( // It will be used only on Redis error as insurance
const rateLimiter = new RateLimiterMemory(
{

@@ -316,3 +358,3 @@ keyPrefix: 'rlflx',

*
* It may be Error if you use Redis, Mongo or Cluster without insurance
* It may be Error if you use Redis, Mongo, MySQL or Cluster without insurance
* { limit2: Error }

@@ -368,7 +410,7 @@ */

#### Options specific to Redis and Mongo
#### Options specific to Redis, Mongo, MySQL
* `inmemoryBlockOnConsumed` `Default: 0` Against DDoS attacks. Blocked key isn't checked by requesting Redis or Mongo.
* `inmemoryBlockOnConsumed` `Default: 0` Against DDoS attacks. Blocked key isn't checked by requesting Redis, MySQL or Mongo.
In-memory blocking works in **current process memory**.
Redis and Mongo are quite fast, however, they may be significantly slowed down on dozens of thousands requests.
Redis, MySQL and Mongo are quite fast, however, they may be significantly slowed down on dozens of thousands requests.

@@ -379,3 +421,3 @@ * `inmemoryBlockDuration` `Default: 0` Block key for `inmemoryBlockDuration` seconds,

* `insuranceLimiter` `Default: undefined` Instance of RateLimiterAbstract extended object to store limits,
when Redis or Mongo comes up with any error.
when Redis, MySQL or Mongo comes up with any error.

@@ -387,2 +429,11 @@ All data from `insuranceLimiter` is NOT copied to parent limiter, when error gone

#### Options specific to MySQL
* `storeClient` `Required` Have to be `mysql2` or `mysql` connection
* `dbName` `Default: 'rtlmtrflx'` Database where limits are stored. It is created during creating a limiter
* `tableName` `Default: equals to 'keyPrefix' option` By default, limiter creates table for each unique `keyPrefix`.
All limits for all limiters are stored in one table if custom name is set.
#### Options specific to Cluster

@@ -413,3 +464,3 @@

* **resolved** with `RateLimiterRes` when point(s) is consumed, so action can be done
* **rejected** only for Redis and Mongo if `insuranceLimiter` isn't setup: when some error happened, where reject reason `rejRes` is Error object
* **rejected** only for Redis, Mongo and MySQL if `insuranceLimiter` isn't setup: when some error happened, where reject reason `rejRes` is Error object
* **rejected** only for RateLimiterCluster if `insuranceLimiter` isn't setup: when `timeoutMs` exceeded, where reject reason `rejRes` is Error object

@@ -416,0 +467,0 @@ * **rejected** when there is no points to be consumed, where reject reason `rejRes` is `RateLimiterRes` object

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