运行 1000 个请求,这样一次只运行 10 个

Posted

技术标签:

【中文标题】运行 1000 个请求,这样一次只运行 10 个【英文标题】:Run 1000 requests so that only 10 runs at a time 【发布时间】:2017-01-01 16:03:59 【问题描述】:

使用 node.js,我想http.get 多个远程 URL,一次只能运行 10 个(或 n 个)。

如果本地发生异常(m次),我也想重试请求,但是当状态码返回错误(5XX、4XX等)时,请求被视为有效。

这对我来说真的很难理解。

问题:

    无法尝试捕获 http.get,因为它是异步的。 需要一种方法来重试失败的请求。 我需要某种信号量来跟踪当前活动的请求计数。 当所有请求完成后,我想在一个列表中获取所有请求 url 和响应状态代码的列表,我想对其进行排序/分组/操作,因此我需要等待所有请求完成。

似乎对于每个异步问题都建议使用 Promise,但我最终嵌套了太多 Promise,并且很快就会变得无法加密。

【问题讨论】:

如果你嵌套了太多的 Promise,从 'then' 调用中更频繁地返回,并在相同的缩进级别上写下一个 'then'。 Throttle amount of promises open at a given time的可能重复 Limit concurrency of promise being run的可能重复 【参考方案1】:

有很多方法可以处理一次运行的 10 个请求。

    异步库 - 使用带有 .parallelLimit() method 的异步库,您可以在其中指定一次要运行的请求数。

    Bluebird Promise 库 - 使用 Bluebird promise library 和 request 库将您的 http.get() 包装成可以返回承诺的东西,然后使用 Promise.map() 并发选项设置为10

    手动编码 - 手动编码您的请求以启动 10,然后每次完成后,再启动另一个。

在所有情况下,您都必须手动编写一些重试代码,并且与所有重试代码一样,您必须非常仔细地确定重试的错误类型、重试的时间、重试之间的退避时间当你最终放弃时(所有你没有指定的东西)。

其他相关答案:

How to make millions of parallel http requests from nodejs app?

Million requests, 10 at a time - manually coded example


我首选的方法是使用 Bluebird 和 promises。包括按顺序重试和结果收集,可能看起来像这样:

const request = require('request');
const Promise = require('bluebird');
const get = Promise.promisify(request.get);

let remoteUrls = [...];    // large array of URLs

const maxRetryCnt = 3;
const retryDelay = 500;

Promise.map(remoteUrls, function(url) 
    let retryCnt = 0;
    function run() 
        return get(url).then(function(result) 
            // do whatever you want with the result here
            return result;
        ).catch(function(err) 
            // decide what your retry strategy is here
            // catch all errors here so other URLs continue to execute
            if (err is of retry type && retryCnt < maxRetryCnt) 
                ++retryCnt;
                // try again after a short delay
                // chain onto previous promise so Promise.map() is still
                // respecting our concurrency value
                return Promise.delay(retryDelay).then(run);
            
            // make value be null if no retries succeeded
            return null;
        );
    
    return run();
, concurrency: 10).then(function(allResults) 
     // everything done here and allResults contains results with null for err URLs
);

【讨论】:

【参考方案2】:

简单的方法是使用async 库,它有一个.parallelLimit 方法可以满足您的需要。

【讨论】:

.parallelLimit 没有提供进行重试的方法,因此无法提供 OP 要求的所有内容。必须添加更多内容。

以上是关于运行 1000 个请求,这样一次只运行 10 个的主要内容,如果未能解决你的问题,请参考以下文章

需要每 2 分钟 ping 1000 个 url

Celery 任务计划(确保一个任务一次只执行一个)

如何在 mfc 中限制一次只运行一个应用程序实例

一次只执行几个线程[重复]

为啥我的 WCF 服务一次只处理 3 个并行请求?

向http服务器发送了很多异步请求,但每次只服务几个请求。