Promise队列中的Bluebird-Queue并发不能按预期工作

时间:2015-06-30 01:26:07

标签: javascript node.js promise bluebird

我通过NodeJS使用bluebird-queue将HTTP端点排队为任务。每个任务都有一个3级Promise依赖,必须在完成之前解决。

一项任务

GET -> endpoint 1 // returns promise
    GET -> other endpoints in async // returns promise
        POST -> final endpoint // return promise

我将20,000个这些任务放入带有queue.add()的bluebird队列,然后调用queue.start()。捕获所有错误,处理程序解析Promise,以便完成任务。

我已将并发设置为50.我最初的期望是队列将在任何给定时间处理50,而是在下一个50开始之前等待前50个完成。

不幸的是,其中一些请求最多可能需要10秒才能完成 - 如果单个请求需要更长时间才能完成,整个队列将停止运行,直到Promise结算。

如果这是预期的行为,我可以做什么/使用什么来确保队列中的任务在任何给定时间处理最多50个任务,而不是一次处理50个任务?

以下是我的配置设置:

var Queue = require('bluebird-queue'),
    queue = new Queue({
        concurrency: 50, 
        delay: 10, // ms
        interval: 1 // ms not quite sure what this means
    });

感谢任何帮助。

2 个答案:

答案 0 :(得分:4)

在阅读bluebird-queue的代码之后,很明显,您所看到的关于并发性的行为是预期的。我同意这有点令人惊讶。似乎没有任何方法可以达到预期的行为。

我建议您尝试promise-queue。基于对代码的快速阅读,它似乎可以像您期望的那样工作。

答案 1 :(得分:1)

您应该在bluebird-queue发布未被Petka Antonov编码的问题。这是一个定制项目,目前相当原始。我很好奇地玩它,因为你的问题听起来很有趣。我已经做了一个例子(下面),它产生了具有不同时间来解决的工人。并且它表明bluebird-queue表现不一致。除了最后一组项目(如您所述)之外的所有项目都在一组中排队,并且所有下一组项目仅在前一组完成时开始。然而,最后一组项目并非如此。您可以使用Nconcurrency来追踪

var Promise = require("bluebird");
var Queue = require('bluebird-queue');
function formatTime(date){
    function pad(value, width){
        width = width || 2;
        if(typeof value !== 'string') value = value.toString();
        if(value.length < width) value = new Array(width - value.length + 1).join('0') + value;
        return value;
    }
    return pad(date.getHours()) + ':' + pad(date.getMinutes()) + ':' + pad(date.getSeconds()) + ':' + pad(date.getMilliseconds(), 3);
}

var N = 20;
var start = function(){
    var queue = new Queue({
        concurrency: 4,
        delay: 10, // ms
        interval: 1 // ms not quite sure what this means
    });
    for(var i = 0; i < N; i++){
        var worker = function(number) {
            return new Promise(function (resolve, reject) {
                console.log(formatTime(new Date()) + ' Starting ' + number);
                setTimeout(function () {
                    console.log(formatTime(new Date()) + '   Finished ' + number);
                    resolve(number);
                }, 500 + (number % 2)*500);
            });
        }.bind(null, i);
        queue.add(worker);
    }
    queue.start().then(function(arg){
        console.log('All finished ' + arg);
    });
};