Tho*_*ggi 53 asynchronous throttling request node.js
我使用mikeal/request来进行API调用.我最频繁使用的API之一(Shopify API).最近推出了一个新的通话限制,我看到的错误如下:
Exceeded 6.0 calls per second for api client. Slow your requests or contact support for higher limits.
Run Code Online (Sandbox Code Playgroud)
我已经进行了升级,但无论我获得多少带宽,我都必须考虑到这一点.对Shopify API的大多数请求都在async.map()函数中,这些函数循环异步请求并收集正文.
我正在寻找任何帮助,也许是一个已经存在的库,它将包裹请求模块并实际阻塞,休眠,限制,分配,管理,同步发出的许多同时请求并限制它们6在一时间 如果不存在这个项目,我没有问题.我只是不知道如何处理这种情况,我希望有某种标准.
我用mikeal/request做了一张票.
Dmi*_*nyi 33
对于替代解决方案,我使用节点速率限制器来包装请求函数,如下所示:
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);
});
};
Run Code Online (Sandbox Code Playgroud)
Cam*_*hez 22
该npm包简单的速率限制似乎是一个很好的解决了这个问题.
而且,它比node-rate-limiter和更容易使用async.queue.
这是一个片段,显示如何将所有请求限制为每秒十个.
var limit = require("simple-rate-limiter");
var request = limit(require("request")).to(10).per(1000);
Run Code Online (Sandbox Code Playgroud)
Dan*_*Dan 14
我遇到了各种API的相同问题.AWS也因节流而闻名.
可以使用几种方法.你提到了async.map()函数.你试过async.queue()吗?队列方法应允许您设置固定限制(如6),超过该数量的任何内容都将放入队列中.
另一个有用的工具是oibackoff.如果您从服务器收到错误并再次尝试,该库将允许您退出您的请求.
包装两个库以确保你的基础都被覆盖是很有用的:async.queue以确保你没有超出限制,并且oibackoff确保你在服务器告诉你的时候获得请求的另一个镜头有一个错误.
在异步模块中,此请求的功能已关闭为"不会修复"
有一个使用leakybucket或令牌桶模型的解决方案,它实现了"限制器"npm模块作为RateLimiter.
RateLimiter,请参见此处的示例:https://github.com/caolan/async/issues/1314#issuecomment-263715550
另一种方法是使用PromiseThrottle,我用过这个,工作示例如下:
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);
});
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
我们可以清楚地看到输出的速率,即每秒5次调用.
我使用现代香草 JS 的解决方案:
function throttleAsync(fn, wait) {
let lastRun = 0;
async function throttled(...args) {
const currentWait = lastRun + wait - Date.now();
const shouldRun = currentWait <= 0;
if (shouldRun) {
lastRun = Date.now();
return await fn(...args);
} else {
return await new Promise(function(resolve) {
setTimeout(function() {
resolve(throttled());
}, currentWait);
});
}
}
return throttled;
}
Run Code Online (Sandbox Code Playgroud)
用法:
const throttledRun = throttleAsync(run, 1000);
Run Code Online (Sandbox Code Playgroud)
其他解决方案不符合我的口味。进一步研究,我发现了promise-ratelimit,它为你提供了一个api,你可以简单地await:
var rate = 2000 // in milliseconds
var throttle = require('promise-ratelimit')(rate)
async function queryExampleApi () {
await throttle()
var response = await get('https://api.example.com/stuff')
return response.body.things
}
Run Code Online (Sandbox Code Playgroud)
上面的示例将确保您最多api.example.com仅每 2000 毫秒进行一次查询。换句话说,第一个请求不会等待2000ms。
| 归档时间: |
|
| 查看次数: |
42431 次 |
| 最近记录: |