【问题标题】:Async requests over an API with request rate limiter带有请求速率限制器的 API 上的异步请求
【发布时间】:2018-05-29 16:31:56
【问题描述】:
我正在一个项目中工作,我需要通过 API 发出请求。这些请求返回有关支持票的数据,但问题是我有大约 500 张票要获取有关数据,每张票都需要一个请求。为了加快请求速度,我尝试构建一个同时生成许多请求的异步例程。但是,由于我正在与之集成的 API 的速率限制器为每秒 10 个请求,因此某些例程会得到“限制超出”的答案。如果我按顺序发出请求,大约需要 5 分钟。
那样,有人在该任务中给我提示吗?我尝试了一些解决方案,例如 NodeJS 的 rate-limiter,但它只是同时生成 10 个请求,并且没有给出任何错误处理,也没有在请求失败时重试。
关于语言,没有限制,项目是用NodeJS编写的,但也有一些python代码,集成其他语言没有问题。
【问题讨论】:
标签:
javascript
python
node.js
api
【解决方案1】:
这样的东西自己创建并不难,它会给你所需的灵活性。
有很多奇特的方法,比如跟踪每个的开始和完成时间,并检查你是否在一秒钟内发送了 10 个。
系统可能还将其限制为 10 个活动请求(即,您不能启动 100 个请求,每秒 10 个,然后让它们全部处理)。
如果您假设这一点,我会说一次启动 10 个,然后让它们完成,然后启动下一批。您也可以启动 10 个,然后每次完成时再启动 1 个。你可以把它想象成“thread pool”。
您可以通过一个简单的变量来跟踪呼叫的数量,从而轻松跟踪这一点。然后,只需检查每秒有多少调用(以避免 1 秒的限制),如果您有可用的“线程”,则触发更多的新请求。
它可能看起来像这样:
const threadLimit = 10;
const rateLimit = 1000; // ms
let activeThreads = 0;
const calls = new Array(100).fill(1).map((_, index) => index); // create an array 0 through 99 just for an example
function run() {
if (calls.length == 0) {
console.log('complete');
return;
}
// threadLimit - activeThreads is how many new threads we can start
for (let i = 0; i < threadLimit - activeThreads && calls.length > 0; i++) {
activeThreads++; // add a thread
call(calls.shift())
.then(done);
}
setInterval(run, rateLimit);
}
function done(val) {
console.log(`Done ${val}`);
activeThreads--; // remove a thread
}
function call(val) {
console.log(`Starting ${val}`);
return new Promise(resolve => waitToFinish(resolve, val));
}
// random function to simulate a network call
function waitToFinish(resolve, val) {
const done = Math.random() < .1; // 10% chance to finish
done && resolve(val)
if (!done) setInterval(() => waitToFinish(resolve, val), 10);
return done;
}
run();
基本上,run() 会根据限制和已完成的数量启动尽可能多的新线程。然后,它只是每秒重复该过程,尽可能添加新的。
您可能需要使用 threadLimit 和 rateLimit 值,因为大多数速率限制系统实际上并不会让您达到极限,并且不会在完成后立即释放它。