Architecture 消息队列体系结构(从客户端到web服务器再到工作服务器)

Architecture 消息队列体系结构(从客户端到web服务器再到工作服务器),architecture,rabbitmq,httprequest,backgroundworker,message-queue,Architecture,Rabbitmq,Httprequest,Backgroundworker,Message Queue,我有一个在Heroku上运行的用NodeJS编写的web服务器。服务器有一个web服务器进程和一个工作进程。web服务器通过RabbitMQ队列成功地向工作者发送消息;工作进程成功地将处理后的数据返回到web服务器。我使用随机生成的Uuid跟踪消息,并确保正确的消息与正确的原始消息配对 在另一个项目中,我让客户端(网站)成功地与web服务器通信。现在,我需要把两者结合起来 我怎样才能做到这一点: 客户端发送HTTP POST Web服务器接收请求并将请求传递到消息队列中 Worker处理请求并返

我有一个在Heroku上运行的用NodeJS编写的web服务器。服务器有一个web服务器进程和一个工作进程。web服务器通过RabbitMQ队列成功地向工作者发送消息;工作进程成功地将处理后的数据返回到web服务器。我使用随机生成的Uuid跟踪消息,并确保正确的消息与正确的原始消息配对

在另一个项目中,我让客户端(网站)成功地与web服务器通信。现在,我需要把两者结合起来

我怎样才能做到这一点:

  • 客户端发送HTTP POST
  • Web服务器接收请求并将请求传递到消息队列中
  • Worker处理请求并返回到web服务器
  • Web服务器将正确的数据返回给客户端,以便客户端可以将响应与原始请求相关联 第四步是我陷入困境的地方。我想我在某个地方读到,客户机应该持续轮询(HTTP POSTs?)web服务器,直到其数据准备就绪。我想我需要在第一步之后回复客户,这样请求就不会超时。任何想法/建议都将不胜感激

    方框图:

    您需要做的简短版本是双向消息传递。您的web应用程序需要是消息生产者和消息消费者。您的后端服务也是如此

    当HTTP请求传入时,web服务器通过RabbitMQ发送消息。后端将在将来的某个时候接收它。同时,web服务器通过HTTP请求发回一个响应,表示发生了什么事情,稍后将通知用户

    如果您使用的是express,它将如下所示:

    
    var router = express.Router();
    router.post("/", postJob);
    
    function postJob(req, res, next){
      req.session.inProgress = true;
    
      var msg = {
        job: "do some work"
      };
    
      jobSender.sendJobRequest(msg, function(err){
        if (err) { return next(err); }
        res.render("some-response");
      });
    }
    
    这段代码做了很多假设,比如
    jobSender
    是一种封装对象,具有跨RabbitMQ发送消息的方法。我相信你可以根据你已经说过的内容填写发送信息的细节

    重要的是,HTTP请求处理程序通过RabbitMQ发送消息,然后将HTTP响应发送回web浏览器

    此时,浏览器可以执行任何需要执行的操作

    在后端,当其他服务完成其工作时,它将需要执行以下两项操作之一:

    1) 在某处更新共享数据库,以便您的web服务器知道已完成的工作(并可以读取状态)

    2) 通过rabbitmq将消息发送回web服务器

    出于各种原因,选项1可能并不总是一个好的选项。从你的问题来看,不管怎样,你想要选择2

    您需要第二个队列—web服务器正在侦听的队列。当web服务器从该队列接收到消息时,它将使用接收状态更新自己的数据库

    此状态可能是“完成”、“进行中”或“错误”或您认为合适的其他状态

    例如,如果您有一条“job status”消息,那么您可能有一个名为“JobStatusReceiver”的抽象来接收状态消息

    像这样一个简单的模块可以从作业状态队列接收消息,并用状态更新本地数据库

    
    var JobStatusReceiver = require("./jobStatusReceiver");
    var someDataObject = require("someDataObject");
    
    var jobStatus = {
    
      listen: function(){
        var receiver = new JobStatusReceiver();
        receiver.receive(function(statusMessage){
    
          someDataObject.status = statusMessage.status;
          someDataObject.data = statusMessage.data;
    
    
          someDataObject.save();
        });
      }
    
    };
    
    module.exports = jobStatus;
    
    请注意,这可能发生在web服务器中,但它不是HTTP请求的一部分。消息是通过带有JobStatusReceiver的RabbitMQ传入的,而不是HTTP请求的一部分

    someDataObject
    对象很可能是来自yoru数据库的对象,因此可以将其保存回数据库

    最后,您需要用数据通知用户已完成操作的部分可以通过多种方式进行

    一般来说,每隔几秒钟对web服务器上的HTTP API进行AJAX调用以查找有效响应是相当容易的

    在浏览器端,这可能非常简单:

    
    var timer = setInterval(function(){
    
      $.ajax({
        url: "/api/check-status",
        success: function(data){
          if (data.complete){
            clearInterval(timer);
            doSomeOtherWork(data);
          }
        })
      });
    
    });
    
    同样,在Express应用程序中,处理“/api/检查状态”,您将使用相同的“someDataObject”模型检查状态:

    
    var someDataObject = require("someDataObject");
    
    var router = new express.Router();
    router.get("/", checkStatus);
    
    function checkStatus(req, res, next){
    
      someDataObject.load(function(err, someData){
        if (err) { return next(err); }
    
        res.json({
          complete: (someData.status === "complete"),
          data: someData.data
        });
    
      });
    
    }
    
    这将有望让你走上正确的道路。当然,我遗漏了很多细节,但希望你能填补遗漏的部分


    p.S.:在我的培训课程中,我介绍了所有这些内容,除了浏览器在计时器上检查状态更新之外。使用RabbitMQ和Node.js启动并运行它是一个完整的包。尽管它使用的是activeMQ,而不是RabbitMQ,但它在这里说,您使用一个相关id设置每个reach请求,您可以使用该id将响应映射到相应的id,这样,您就可以轻松地用正确的请求响应web客户端。

    这是一个需要状态更新的长期运行过程吗?或者这是来自后端的一个非常快速的响应,原始HTTP请求应该从该后端服务获得一个带有数据的响应?我认为状态更新。有时,后端将是30秒以上。是的,对于超过一秒左右的时间,状态更新是一种方式。我很快会发布答案。你不能使用WebSocket吗?只要客户留在您的网站上,这应该是可能的。这是一个很好的方法,我想它可以与pub/sub模式混合,而不是池。