Search code examples
javascriptnode.jsapirequestlimit

Node.JS: Best way to handle max requests per minute to a server


I'm sorry if this question as already been answered and I hope I'm not breaking any SO rule, if so, in advance I apologise... I was wondering what was the best way to handle a request limiter? I've seen a bunch of throttles and rate-limiters online but I'm not sure how or if it could apply in my case.

I'm doing a bunch of [OUTGOING] request-promises based on an Array and on a server I can only make 90 request per minute. My request-promises are generated by this command: return Promise.all(array.map(request)).

I was thinking to handle it like this:

var i = 0;

return rp({
        url: uri,
        json: true,
      }).then((data) => {
        if (i <=90) {
          i ++;
          return data;
        } else {
          return i;
        }
      });

but I'm not sure if it will be a really effective way to handle it plus, I'm not sure how to handle the time relation yet... :S

Thanks in advance for your help and sorry I'm still a huge beginner...


Solution

  • If the requests are started from different code parts, it might be useful to implement sth like a server queue which awaits the request until it is allowed to do so. The general handler:

    var fromUrl = new Map();
    
    function Server(url, maxPerMinute){
     if(fromUrl.has(url)) return fromUrl.get(url);
     fromUrl.set(url,this);
    
      this.tld = url;
      this.maxPerMinute = maxPerMinute;
      this.queue = [];
      this.running = false;
    
    }
    
    
      Server.prototype ={
       run(d){
        if(this.running && !d) return;
        var curr = this.queue.shift();
        if(!curr){
          this.running = false;
          return;
        }
       var [url,resolve] = curr;
       Promise.all([
         request(this.tld + url),
         new Promise(res => setTimeout(res, 1000*60/this.maxPerMinute)
        ]).then(([res]) => {
           resolve(res);
           this.run(true);
        });
      },
      request(url){
       return new Promise(res => {
          this.queue.push([url,res]);
          this.run();
        });
      }
    };
    
    module.exports = Server;
    

    Usable like this:

     var google = new require("server")("http://google.com");
    
    google.maxPerMinute = 90;
    
    google.request("/api/v3/hidden/service").then(res => ...);