串行处理处理异步的消息队列

时间:2016-08-19 16:51:34

标签: javascript node.js asynchronous

当处理消息的函数异步操作消息时,如何处理按函数按顺序传递的一系列消息?

一个例子:

var processMessage = function(msg) {
  switch (msg.action) {
    case "doFoo":
      this.processFoo(()=> {
        // `foo` is done processing
      });
    break;
    case "doBar":
      this.processBar(()=> {
        // `bar` is done processing
      });
    break;
    case "doBaz":
      this.processBaz(()=> {
        // `baz` is done processing
      });
     break;
  }
}

注释

  • 我当然可以推送数组中的项目,然后使用async eachSeries来处理消息数组
  • 然而,消息不断传递,从而填充了更多要处理的项目,导致处理失败

这类问题是否存在事实上/标准的解决方案?

1 个答案:

答案 0 :(得分:2)

这是一个一般方案:

  1. 当新邮件到达时,请检查标记以查看您是否已处理邮件。如果设置了标志,只需将消息添加到队列中。
  2. 如果未设置该标志,请检查队列,如果队列中有消息,则从队列中删除该消息。
  3. 当您开始处理该消息时,请设置一个标志,指示您现在正在处理消息。
  4. 启动处理消息的异步操作
  5. 当发生回信以表示异步消息完成时,清除该标志以指示您正处于处理过程中并递归调用再次从步骤2开始的函数。
  6. 您在两点触发处理新邮件。首先,当新消息到达且您尚未处理消息时,其次在处理其他消息时,您将检查在处理过程中是否有其他任何内容添加到队列中。

    您维护一个inProcessing类型标志,这样当另一条消息已经处于处理过程中时,您不会无意中开始处理传入消息(这会强制您请求的串行执行)。

    你必须严格处理错误条件,这样标志永远不会卡住,所以你的队列处理永远不会停滞。

    在伪代码中(假设这些是包含数组作为队列的队列对象上的方法):

    addQueue: function(msg) {
        if (!this.inProcess) {
            // not currently processing anything so just process the message
            this.processMessage(msg);
        } else {
            this.queue.push(msg);
        }
    },
    
    
    processMessage: function(msg, completeFn) {
         var self = this;
         // must set this flag before going async
         self.inProcess = true;
         // asynchronously process this message
         someAsyncProcessing(msg, function(err) {
             self.inProcess = false;
             if (completeFn) {
                 completeFn(err);
             }
             // see if anything else is in the queue to process
             if (self.queue.length) {
                 // pull out oldest message and process it
                 var msg = self.queue.shift();
                 self.processMessage(msg);
             }
         });
    }