Skip to content

Consume points evenly

Roman edited this page May 8, 2021 · 2 revisions

This example is useful, when points should be consumed evenly over duration, e.g. your limiter has 10 points per hour, but it must allow to consume a point once per 6 minutes.

You can create two limiters:

  1. main limiter as points storage with allowance of 10 points per hour.
  2. interval limiter, which make sure only one point is consumed every 6 minutes.

Interval limiter rejects all tries, when point already consumed in current 6 minutes duration.

const {RateLimiterMemory} = require('rate-limiter-flexible');

module.exports = class RateLimiterEven {
    constructor(options = {}, callback) {
        const mainLimiter = new RateLimiterMemory(Object.assign({}, options, {
            keyPrefix: 'main'
        }), callback);

        const intervalLimiter = new RateLimiterMemory(Object.assign({}, options, {
            keyPrefix: 'interval',
            points: 1,
            duration: Math.ceil(this.duration / this.points)
        }));

        this._mainLimiter = mainLimiter;
        this._intervalLimiter = intervalLimiter;
    }

    async consume(key, points = 1, options = {}) {
        await this._intervalLimiter.consume(key, points, options);
        return this._mainLimiter.consume(key, points, options);
    }

    penalty(key, points = 1) {
        return this._mainLimiter.penalty(key, points);
    }

    reward(key, points = 1) {
        return this._mainLimiter.reward(key, points);
    }

    get(key) {
        return this._mainLimiter.get(key);
    }

    set(key, points, secDuration) {
        return this._mainLimiter.set(key, points, secDuration);
    }

    block(key, secDuration) {
        return this._mainLimiter.block(key, secDuration);
    }

    delete(key) {
        return this._mainLimiter.delete(key);
    }
}

You can also extend it from RateLimiterAbstract, if you want to use it with RateLimiterQueue or RateLimiterUnion.