Javascript 如何使用rxjs处理http并发请求和速率限制
此应用程序需要向外部API发出100个HTTP请求。外部API受速率限制 下面是使用Javascript 如何使用rxjs处理http并发请求和速率限制,javascript,node.js,rxjs,Javascript,Node.js,Rxjs,此应用程序需要向外部API发出100个HTTP请求。外部API受速率限制 下面是使用RXJS处理速率限制的工作解决方案,使用map操作符确定响应是否通知我们速率限制(在本例中为401),如果出现错误,还使用retryWhen延迟2秒并继续 但是,如果我们将代码从处理1个HTTP请求改为现在处理100个或更多HTTP请求,这是可行的。这个过程是按顺序处理的,对于我的usecase来说不够快 代码 const httpRequest = async () => { return axios
RXJS
处理速率限制的工作解决方案,使用map操作符确定响应是否通知我们速率限制(在本例中为401),如果出现错误,还使用retryWhen
延迟2秒并继续
但是,如果我们将代码从处理1个HTTP请求改为现在处理100个或更多HTTP请求,这是可行的。这个过程是按顺序处理的,对于我的usecase
来说不够快
代码
const httpRequest = async () => {
return axios("https://jsonplaceholder.typicode.com/todos/1")
}
export const httpRequestReactive = async () => {
const $obserbable = defer(() => from(httpRequest()));
const result = await $obserbable.pipe(
map((res) => handleRateLimit(res)),
retryWhen((errors) => errors.pipe(delay(2000), take(5))),
).toPromise();
return result;
};
const handleRateLimit = (response) => {
if (response.status === 401) {
console.log("RATE LIMIT")
throw response;
}
return response;
}
const main = async () => {
const responseReactive = await httpRequestReactive()
return responseReactive;
}
main().then((res) => {
console.log("results: ", res)
}).catch((err) => {
console.log("errors:: ", err)
})
我知道这个API能够在速率限制之前处理25个请求,然后我必须等待2秒钟。因此,我想一次批处理25个请求,这是我需要处理并发性的地方,类似于Promise.all()
下面您可以看到我使用了mergeAll
。它接受一个并发值。这似乎有效
代码(并发)
问题:
mergeAll
而不是返回一个包含100个元素的结果数组,类似于Promise.all()
我只剩下1个HTTP响应mergeAll
。我最初的代码假设是,如果一个单独的请求有速率限制,它应该重试该单个请求。但是,当我引入mergeAll
时,如果一个请求的速率受限,是否会对批处理中的每个请求进行重试(这是我不希望发生的)。
更新
现在我有了一个响应数组,在进一步测试后,我可以看到im在数组中的响应比我预期的要多。例如,我留下了129条回复,我预计最多会有100条回复。这让我相信mergeAll和我的利率限制处理程序并没有按照我希望的方式工作。如果一个请求有速率限制,它会重试整个批中的所有请求吗
我希望它在遇到速率受限的请求时暂停,重试单个请求,然后继续批处理中的其余请求。
请查看下面的stackblitz(不幸的是,我找不到具有速率受限端点的伪/占位符api)只需在流的末尾添加
toArray()
操作符即可
参见stackblitz:太好了,这确实给了我一系列的回应。我现在剩下的第二个问题是处理mergeAll的速率限制。
export const httpRequestReactiveConcurrent = async () => {
const payloads = new Array(100).fill({});
const source$ = from(payloads.map(x => defer(() => httpRequest())));
const result = await source$.pipe(
mergeAll(25),
// tap((res) => console.log(res.status, res.headers)),
map((res) => handleRateLimit(res)),
retryWhen((errors) => errors.pipe(delay(1000), take(5))),
).toPromise();
return result;
};