限制和排队API请求由于每秒上限

我正在使用mikeal /请求进行API调用。 我最经常使用的API之一(Shopify API)。 最近推出了一个新的呼叫限制 ,我看到像这样的错误:

Exceeded 6.0 calls per second for api client. Slow your requests or contact support for higher limits.

我已经得到了升级,但是无论我得到多less带宽,我都必须考虑到这一点。 Shopify API的大部分请求都在async.map()函数中,这些函数循环asynchronous请求并收集这些主体。

我正在寻找任何帮助,可能是一个已经存在的库,它将环绕请求模块,实际上阻塞,hibernate,扼制,分配,pipe理asynchronous触发的多个同时请求,并限制它们说6请求一次。 如果这个项目不存在,我就没有问题了。 我只是不知道如何处理这种情况,我希望有某种标准。

我用麦克风/请求做了一张票。

我遇到了与各种API相同的问题。 AWS也因节stream而闻名。

可以使用几种方法。 你提到了async.map()函数。 你有没有尝试过async.queue() ? 队列方法应该允许你设置一个可靠的限制(比如6),超过这个数量的任何东西都会被放入队列中。

另一个有用的工具是oibackoff 。 如果您从服务器收到错误并重试,该库将允许您退回请求。

包装这两个库以确保您的基础都被覆盖是非常有用的:async.queue确保您不会超出限制,并且oibackoff可以确保在服务器告诉您时再次获得请求有一个错误。

对于另一种解决scheme,我使用节点速率限制器来包装请求函数,如下所示:

 var request = require('request'); var RateLimiter = require('limiter').RateLimiter; var limiter = new RateLimiter(1, 100); // at most 1 request every 100 ms var throttledRequest = function() { var requestArgs = arguments; limiter.removeTokens(1, function() { request.apply(this, requestArgs); }); }; 

npm包简单限制器似乎是解决这个问题的一个很好的方法。

而且,比node-rate-limiterasync.queue更容易使用。

这是一个片段,展示了如何限制每秒10个请求。

 var limit = require("simple-rate-limiter"); var request = limit(require("request")).to(10).per(1000); 

这是我的解决scheme使用库request-promiseaxios并包装在这个承诺的呼吁。

 var Promise = require("bluebird") // http://stackoverflow.com/questions/28459812/way-to-provide-this-to-the-global-scope#28459875 // http://stackoverflow.com/questions/27561158/timed-promise-queue-throttle module.exports = promiseDebounce function promiseDebounce(fn, delay, count) { var working = 0, queue = []; function work() { if ((queue.length === 0) || (working === count)) return; working++; Promise.delay(delay).tap(function () { working--; }).then(work); var next = queue.shift(); next[2](fn.apply(next[0], next[1])); } return function debounced() { var args = arguments; return new Promise(function(resolve){ queue.push([this, args, resolve]); if (working < count) work(); }.bind(this)); } 

在asynchronous模块中,此请求的function被closures为“不会修复”

  • 2016年给出的理由是“妥善pipe理这种结构是一个难题”。 请参阅此处的右侧: https : //github.com/caolan/async/issues/1314
  • 2013年的原因是“不会扩展到多个进程”请参阅: https : //github.com/caolan/async/issues/37#issuecomment-14336237

有一个使用leakybucket或令牌桶模型的解决scheme,它实现了“limiter”npm模块作为RateLimiter。

看到这里的例子: https : //github.com/caolan/async/issues/1314#issuecomment-263715550

 var PromiseThrottle = require('promise-throttle'); let RATE_PER_SECOND = 5; // 5 = 5 per second, 0.5 = 1 per every 2 seconds var pto = new PromiseThrottle({ requestsPerSecond: RATE_PER_SECOND, // up to 1 request per second promiseImplementation: Promise // the Promise library you are using }); let timeStart = Date.now(); var myPromiseFunction = function (arg) { return new Promise(function (resolve, reject) { console.log("myPromiseFunction: " + arg + ", " + (Date.now() - timeStart) / 1000); let response = arg; return resolve(response); }); }; let NUMBER_OF_REQUESTS = 15; let promiseArray = []; for (let i = 1; i <= NUMBER_OF_REQUESTS; i++) { promiseArray.push( pto .add(myPromiseFunction.bind(this, i)) // passing am argument using bind() ); } Promise .all(promiseArray) .then(function (allResponsesArray) { // [1 .. 100] console.log("All results: " + allResponsesArray); }); 

输出:

 myPromiseFunction: 1, 0.031 myPromiseFunction: 2, 0.201 myPromiseFunction: 3, 0.401 myPromiseFunction: 4, 0.602 myPromiseFunction: 5, 0.803 myPromiseFunction: 6, 1.003 myPromiseFunction: 7, 1.204 myPromiseFunction: 8, 1.404 myPromiseFunction: 9, 1.605 myPromiseFunction: 10, 1.806 myPromiseFunction: 11, 2.007 myPromiseFunction: 12, 2.208 myPromiseFunction: 13, 2.409 myPromiseFunction: 14, 2.61 myPromiseFunction: 15, 2.811 All results: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 

我们可以清楚地看到输出的速率,即每秒5个呼叫。