【问题标题】:long polling and queue to hold requests长轮询和队列以保持请求
【发布时间】:2013-06-10 10:02:46
【问题描述】:

POST /add-request - 添加新请求

POST /get-request - 返回第一个(最旧的)请求

我有许多被称为“奴隶”的 Java 应用程序。他们的工作是调用POST /get-request 来获取处理请求,并在处理后将其保存到数据库中。所有请求都存储在 mongoDB 中。 /add-request 只是将请求添加到数据库。 /get-request 使用 findAndModify mongo 查询从队列中获取第一个请求并将其状态设置为“处理”(需要此状态以避免从 DB 获取两次相同请求的情况)。现在奴隶只需每 2 秒调用一次 api。但我想在这里使用一些长轮询。它应该是这样的:

  1. 我必须在队列中保留从属请求。
  2. 如果没有新请求,我必须为每个从属请求设置超时以在 4 秒后发送例如 404。
  3. 当通过/add-request 添加新请求时,我必须从队列中获取第一个从属请求,将其从该队列中删除,从数据库获取请求并将其发送到该从属。

所以假设我必须处理程序(我正在使用 express):

function addRequest(req,res,next){ 
    // add request to db and check if there is waiting slave request in queue
    // if there is one remove it from queue, clear timeout on it, get request from db
    // and send it to slave
}

function getRequest(req,res,next){ 
    // get request from db - if there is no request add this slave request to queue
    // set timeout to send 404 after 4 seconds
}

问题出在队列上 - 我尝试了许多 qpproaches,但没有任何“同步”,我无法使其工作......当两个快速处理程序对其进行操作时,是否可以确保队列中的一致性同时?问题在于超时后从队列中删除请求。我必须使用一些 uid 在队列中搜索请求,然后将其删除...

也许有一些库/工具可以实现我的目标?


当没有请求slave处理时返回404。 我希望从属设备尽快获取新请求 - 所以如果我会立即返回响应(新请求或没有请求时的 404),那么每个从属设备将不得不一直不停地调用 api 并且它会产生影响我认为关于服务器性能。所以我希望每个从服务器在返回任何数据之前在服务器上“保持”请求 4 秒。

【问题讨论】:

  • 4 秒超时是为了什么?为什么不能立即返回?
  • 我找不到具体的问题,但使用findAndModify 如此答案所示可以帮助多个客户:stackoverflow.com/a/16182474/95190。 404我也看不懂,是不是找不到资源?

标签: node.js mongodb long-polling


【解决方案1】:

确保您尽快处理排队请求的有趣技术。

在同步队列方面,没有必要因为 Node 是单线程的。您无需担心像 Java 这样的多线程问题,我认为这非常好。

这里有一些可能有效的粗略代码。添加错误处理和正确的 Mongo db 调用。

var queue = {};

function addJob(req,res,next){ 
  var job = req.body;
  mongo.add(job, function(err){ // pseudo code to add request to db. 
    res.send(200); // request is stored, no need to keep the client waiting.
    // find a random slave in the queue:
    for(var slaveName in queue) {
      queue[slaveName].send(job);
      delete queue[slaveName];
      break;
    }      
  });
}

function getRequest(req,res,next){ 
  // get request from db - if there is no request add this slave request to queue
  mongo.get(..., function(err, job){
    if(job){
      return res.send(job);
    }
    // no job, add slave to queue:
    var slaveName = req.body;
    queue[slaveName] = res;

    // set timeout to send 404 after 4 seconds
    setTimeout(function(){
      delete queue[slaveName];
      res.send(404);
    }, 4000);
  }
}

【讨论】:

  • 问题是当长时间没有新作业时,队列数组会一直增长(填充空)。这是我遇到的问题 - 我尝试在 4 秒后删除数组索引,但随后所有索引都更改了,并且 setTimeout 中使用的索引不再有效。现在我假设当调用超时函数时,它意味着它“属于”队列中最旧的从站,所以队列前面的从站(我使用 FIFO)而不是slave = queue[index],我使用slave = queue.shift。但不知道这是不是一个好的假设......
  • 我想了想,上面的假设并不好,因为超时函数可能会发送 404 到从队列中的第一个被转移到发送作业后被推送到队列的从站。所以我认为有必要在队列中存储一些counter(这个计数器就像作业的id)和作业,然后在超时函数中:slave = queue[0]; if(slave && slave.counter <= counter) { queue.shift(); ... }
  • 我已经更改了代码,使其不使用索引,而是使用从站/响应上的标记。
  • 但是,如果没有任何新的作业并且从站将继续尝试获取请求,那么队列数组将永远增长(带有标记集的 res 对象) - 像这样:[res,res,res, res,res,...] - 我希望避免这种情况,因为例如 24 小时内可能没有新请求。但我想如果您在代码中使用上述标记,则可以在 queue.push(res); 行之后(或之前)添加行 while(queue[0] && queue[0].used) queue.shift(); - 如果我是对的,请编辑您的代码,我会接受您的回答。跨度>
  • 我已编辑答案以使用对象作为队列而不是数组。它工作的主要要求是从服务器在请求正文中传入一个唯一的 id。你也可以自己生成一个唯一的 id。
猜你喜欢
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 2019-05-22
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
相关资源
最近更新 更多