对 API 调用队列进行速率限制并返回结果 [英] Rate limiting a queue of API calls and returning the results

查看:30
本文介绍了对 API 调用队列进行速率限制并返回结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在遍历一个数组并使用 async/await 为每个成员调用 API,然后将结果推送到另一个返回的数组中.

I'm looping through an array and making an API call for each member using async/await, I then push the result into another array which is returned.

// My current function
async requestForEach(repos) {
    const result = [];
    for (const repo of repos) {
        result.push(await this.doSomething(repo.name));
    }
    return result;
}

// doSomething()
const AWS = require('aws-sdk');
const codecommit = new AWS.CodeCommit();
async doSomething(repoName){
    return (await codecommit.listBranches({
        repoName
    }).promise()).branches;
}

我的问题是我的速率受到限制.如果我捕获并打印错误,我会得到..

My issue is I'm getting rate limited. If I catch and print the error I get..

ThrottlingException: Rate exceeded {
  // Call stack here
  code: 'ThrottlingException',
  time: 2020-08-16T15:52:56.632Z,
  requestId: '****-****-****-****-****',
  statusCode: 400,
  retryable: true
}

可以在此处找到我正在使用的 API 的文档 - https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CodeCommit.html#listBranches-property

Documentation for the API I'm using can be found here - https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CodeCommit.html#listBranches-property

我研究了选项,这个异步库似乎是流行的选择.

I looked into options and this async library seemed to be the popular option.

使用 async.queue()..

Using async.queue()..

添加到队列中的任务是并行处理的(直到并发限制).如果所有worker都在进行中,则任务排队直到一个可用.一旦工人完成一项任务,那任务的回调被调用.

Tasks added to the queue are processed in parallel (up to the concurrency limit). If all workers are in progress, the task is queued until one becomes available. Once a worker completes a task, that task's callback is called.

// create a queue object with concurrency 2
var q = async.queue(function(task, callback) {
    console.log('hello ' + task.name);
    callback();
}, 2);

显然我无法从回调函数中取回值,那么我应该如何解决这个问题?

Obviously I cant get the value back from within the callback function, so how should I approach this problem?

推荐答案

顺序 for ... of 循环对我来说看起来不错.您可以为每次迭代添加默认延迟以使其变慢,但您也可以稍后在请求失败时简单地重试请求,因为的节流.请注意,这种方法仅适用于您的应用中只有单一请求源(不是对 requestForEach 的多个并发调用)时,否则您可能需要全局协调.

The sequential for … of loop looks good to me. You can add a default delay for each iteration to make it slower, but you can also simply retry requests later when they fail because of throttling. Notice that this approach only works well when you have only a single source of requests in your app (not multiple concurrent calls to requestForEach), otherwise you'd probably need global coordination.

async doSomething(repoName) {
    while (true) {
        try {
            const data = await codecommit.listBranches({
                repoName
            }).promise();
            return data.branches;
        } catch(err) {
            if (err.code == 'ThrottlingException') { // if (err.retryable) {
                await delay(err.retryDelay ?? 1000);
                continue;
            } else {
                throw err;
            }
        }
    }
}
function delay(time) {
    return new Promise(resolve => {
        setTimeout(resolve, time);
    });
}

代替 while (true) 循环,递归方法可能看起来更好.请注意,在生产代码中,您需要限制重试次数,以便您的循环不会无限运行.

Instead of the while (true) loop a recursive approach might look nicer. Notice that in production code you'll want to have a limit on the number of retries so that your loop never runs infinitely.

这篇关于对 API 调用队列进行速率限制并返回结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆