Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throttle only supports synchronous datastores #381

Closed
brycebaril opened this issue Apr 18, 2013 · 8 comments
Closed

Throttle only supports synchronous datastores #381

brycebaril opened this issue Apr 18, 2013 · 8 comments

Comments

@brycebaril
Copy link

From the API Guide:

In some circumstances, you want to offload this into a shared system, such as Redis, if you have a fleet of API servers and you're not getting steady and/or uniform request distribution. To enable this, you can pass in options.tokensTable, which is simply any Object that supports put and get with a String key, and an Object value.

I went to create a Redis tokensTable and quickly noticed that it won't actually work because for Redis the tokensTable.get needs to be asynchronous. The way that TokenBucket works also expects the same bucket instance to be used.

So I went and made backwards-compatible modifications to tokens.js that allow you to use either synchronous or asynchronus TokensTable implementations, which only changes the api for async ones such that it doesn't break any existing versions.

I've got it nearly there, but the more I work on it the more I think a larger-order refactor of the throttle.js would make things a lot easier (or at least cleaner). I don't mind doing this, but I'm thinking if I did, it may be a reasonable time to extract it from restify into its own module.

So my questions are:

First: Am I missing something here that would make it feasible to use an async TokensTable with the current implementation and wasting my time?

Second: If I make a new external throttle module that supports both the backwards-compatible synchronous TokensTable and asynchronous versions, would you accept a pull request that removes the existing implementation for a dependency on the new one?

@mcavage
Copy link
Contributor

mcavage commented Jul 19, 2013

Hi,

No, it probably needs to be refactored to work with redis or something. And yes, I would happily offload this; I'd probably leave what's there in, and just point people at the external one.

@gergelyke
Copy link
Member

@brycebaril did you manage to pull this off?

@brycebaril
Copy link
Author

@gergelyke Yes, to an extent -- I made https://npmjs.org/package/tokenthrottle-redis which you should be able to plug in similarly to restify. It is heavily based on @mcavage 's implementation.

I haven't gone through the effort of writing up how to plug it into restify, however.

@gergelyke
Copy link
Member

Could you do that please?

@mcavage
Copy link
Contributor

mcavage commented Feb 7, 2014

Having looked briefly at tokenthrottle I'd definitely want to merge this
functionality back into restify (having an async way to get a throttle
decision) - the redis one I don't really want to ship with (restify is
heavy enough w/o adding another big dep on redis), but we can certainly get
this unified so there's a friendly way for others to do so.

On Fri, Feb 7, 2014 at 8:19 AM, Bryce Baril notifications@github.comwrote:

@gergelyke https://github.com/gergelyke Yes, to an extent -- I made
https://npmjs.org/package/tokenthrottle-redis which you should be able to
plug in similarly to restify. It is heavily based on @mcavagehttps://github.com/mcavage's implementation.

I haven't gone through the effort of writing up how to plug it into
restify, however.

Reply to this email directly or view it on GitHubhttps://github.com//issues/381#issuecomment-34460386
.

@ishbu
Copy link

ishbu commented Jan 23, 2015

Just finished up a project where we needed a redis backed store for our throttling. Utilized https://npmjs.org/package/tokenthrottle-redis by @brycebaril

Here's a quick snippet of the pattern I used:

// Create restify server
var restify = require('restify');
var server = restify.createServer({name:'my-api'});

// Create a redis client
var redisClient = require("redis").createClient()

// Create a throttle with 100 access limit per second.
var throttle = require("tokenthrottle-redis")({rate: 100, expiry: 86400}, redisClient);

// Add a simple username based throttling middleware
server.use(function(req, res, next) {
  var key = req.username;
  if (!key) return next();

  throttle.rateLimit(key, function(err, limited) {
    if (err) return next(err);

    req.log.trace('Throttle(%s): n', limitKey);

    if (limited) {
      return next(new Error("Rate limit exceeded, please slow down."));
    }
    else {
      return next()
    }
  });
});

If you need something more configurable, you could turn this into a configurable middleware, similar to the throttle plugin that ships with restify. But for my purposes, only needed username throttling and no overrides for example.

@micahr micahr added this to the Backlog milestone Jun 18, 2015
@micahr
Copy link
Member

micahr commented Jun 18, 2015

This is the same as #518, will close #518 in favor of this one.

retrohacker pushed a commit that referenced this issue Apr 29, 2017
Closes:

#289
#381
#474
#575
#790
#633
#717
#576
#576
#909
#875
#860
#853
#850
#829
#813
#801
#921
#1101
#1019
#989
#632
#708
#737
#859
#1326
#1327
#927
#1099
#1068
#1040
#1035
#957
#948
#1134
#1136
#1183
#1206
#1286
#1323

> Note: this issue closes _but does not resolve_ the issues listed, we are just tracking them in another medium
@AMorgaut
Copy link

I was looking for a more configurable rate limit module
We are using memcached instead au redis

this nest plugin does axactly what we want
https://github.com/nestjs/throttler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants