具有请求承诺的Node.js API请求限制

时间:2016-06-27 08:10:02

标签: javascript node.js limit throttling

我试图从我的node.js应用程序中获取REST API端点,如下所示:

var people = [];
for(var i=0; i<n; i++) {
    //create person
    people.push(person);
}
return Promise.all(people.map(create3APIRequestPromises));

其中create3APIRequestPromises大致如下:

// APIRequestPromise = require('request-promise')(options);
return Promise.all([APIRequestPromise1, APIRequestPromise2, APIRequestPromise3]);

代码对少数人来说都能正常运行,但是如果我增加太多,它就会开始失败。我相信这种失败是由提供REST API限制我的使用的服务引起的。所以,我的问题是什么是限制我发送的请求数量的最佳方式,即每秒10次。

我已经阅读了有关节点速率限制器的内容,但我看不出它如何适应我上面使用'request-promise'所写的承诺(也许这个模块不可能,所以也许你可以提出另一种选择)。

感谢。

2 个答案:

答案 0 :(得分:1)

我认为在你的情况下最好在发出请求之间使用简单的时间填充。要做到这一点,你应该将请求分成系列,并在每个组前面加上延迟。我意识到example。用法是:

// Create timepad function
var timePad = createTimePad(5, 10e3); // 5 requests each 10 seconds

// Iterate over people
return Promise.all(
  people.map(
    (human) => timePad().then(() => create3APIRequestPromises(human))
  )
);

时间垫创建功能:

// Create timepad function where timeout is timeout between calls and series is the maximum
// number of calls that will be done simultaneously
function createTimePad(series = 10, timeout = 1000) {
  var seriesCounter = 0;
  var delay = 0;

  return () => {
    return new Promise((resolve) => {
      if (--seriesCounter <= 0) {
        delay += timeout;
        seriesCounter = series;
      }

      setTimeout(resolve, delay);
    });
  };
}

它非常简单,可以根据您的意愿将请求拆分为可变大小的组。

答案 1 :(得分:0)

嗯,这确实是一个很好的问题。我有同样的问题,意识到还没有人解决它,并开始实施quota。它已经涵盖了您的用例。

像这样创建你的经理:

var quota = require('quota');

var manager = new quota.Manager({
    backoff: 'timeout'
});

// 10 new requests per second
manager.addRule({
    name: 'main',
    limit: 10,
    window: 1000,
    throttling: 'window-sliding',
    queueing: 'fifo',
    resource: 'requests'
});

var quotaServer = new quota.Server();
quotaServer.addManager('custom', manager);

var quotaClient = new quota.Client(quotaServer);

然后通过这个包装器调用你的每个请求:

var request = require('request-promise');

function requestThrottled(options) {

    var _grant;

    return quotaClient.requestQuota('custom', {}, { requests: 1 }, {
        maxWait: 60000 // Each request will be queued for 60 seconds and discarded if it didn't get a slot to be executed until then
    })
            .then(function (grant) {

                _grant = grant;

                return request(options);

            })
            .finally(function () {

                if (_grant) {
                    _grant.dismiss();
                }

            });

}

您可以像以前一样提出要求:

Promise.all([
    requestThrottled(optionsRequest1),
    requestThrottled(optionsRequest2),
    requestThrottled(optionsRequest3)
])