node.js在使用setTimeout时处理流回压

时间:2014-08-04 20:19:48

标签: javascript node.js asynchronous concurrency

这是我在之前的问题中遇到的另一个问题的后续问题:

nodejs: read from file and store to db, limit maximum concurrent db operations

问题:

我想稍后重新安排一些操作,但是这会破坏我处理背压的方法。

详情:

我有一个CSV文件,我正在以流的形式阅读,并使用转换转换为JSON,然后将每行异步存储到数据库。

当变换处理行时,它们被放置在异步队列上,该队列负责发出数据库操作。

E.g。

parser._transform = function(data, encoding, done) {

    var tick = this._parseRow(data);

    dbQueue.push(tick, function(err, result) {
      if (typeof(err) != 'undefined') { console.log(err) }
    });

    this.push(tick);
    done();
}

当队列饱和/空时,通过暂停和恢复解析器来处理背压:

dbQueue.saturated = function() {
  parser.pause();
}

dbQueue.empty = function() {
  parser.resume();
}

我一直试图做的改变是,当一个项目从队列中取出时,它将在未来有条件地重新安排一段时间(100ms):

var dbQueue = async.queue(function(data, callback) {
  if (condition) {
    // re-schedule operation by adding back to queue 100ms later
    setTimeout(function(data, callback) {
        dbQueue.push(data, function(err, result){
      });
    }, 100, data, callback);
  } else {
    //execute the db store
     ... ...
  }
}

我认为我的问题是现在很多操作都会花费大部分时间在setTimeout中,因此dbQueue将为空,并且转换流的背压未按要求处理。

我尝试过几次尝试使用max_ops和running_ops等计数器来确保暂停/恢复流,但是没有成功。

在node.js中是否有更惯用的处理方式?

1 个答案:

答案 0 :(得分:0)

由于这看起来像是一个外部条件,而不是与dbQueue正在做什么相关的东西,而不是在条件发生时将数据重新插入队列,我会暂停dbQueue。例如,假设您的条件是数据库由于某种原因而断开连接,并且您可以监听该事件。在这种情况下,您可以执行类似于dbQueue饱和/空时您正在执行的操作:

db.on('disconnect', function() {
    dbQueue.pause();
});

db.on('connect', function() {
    dbQueue.resume();
});

这通常比等待一些预先确定的超时更好。话虽如此,有时等待超时是唯一的选择。在这种情况下,您可以执行类似的操作,但不要等待单独的事件触发resume(),只需使用setTimeout()

db.on('disconnect', function() {
    dbQueue.pause();
    setTimeout(function() {
        dbQueue.resume();
    });
});

注意:如果我们真的在这里讨论数据库断开连接,那么如果在100ms不存在的情况下出现db错误,您可能还想暂停/恢复dbQueue有足够的时间让数据库重新连接

如果你有一个更具体的条件,你正在寻找,并且你愿意分享它是什么,我可以给你一个更好的例子:)