使用AMQP维护与远程工作程序的长期连接

时间:2017-04-22 13:32:01

标签: javascript rabbitmq amqp worker

我试图模拟以下场景

服务器发送' START'通过amqp对工作进程执行的操作如下(假设先前提供channelaction,并且操作为START并且有一些有效负载。)

channel.assertQueue('', { exclusive: true }).then(({ queue }) => {
  const cId = uuid()

  channel.consume(queue, (msg) => {
    if (msg.properties.correlationId === cId) {
      const response = JSON.parse(msg.content.toString())
      console.log('response', response)
      resolve(response)
    }
  }, { noAck: true })

  const msg = JSON.stringify(action)
  channel.sendToQueue(
    QUEUE_NAME,
    new Buffer(msg),
    { correlationId: cId, replyTo: queue }
  )
}, reject)

工作人员获得START action以及correlationIdreplyTo队列名称,将有效负载添加到其自己的内部事务列表中,并响应{{1使用' START_SUCCESS'排队动作。

现在,工作人员将查看要执行的操作的内部列表并执行这些操作,并发出“更新”消息。通过相同的replyTo队列将操作返回到服务器,因此服务器需要知道继续监听该队列以进行更新,并且需要知道哪个工作正在处理任何特定任务的更新。服务器足够智能,可以知道特定任务已经启动,因此在这种情况下不会再次发送它。

但是,当工作人员停止执行任务时,服务器需要知道哪个工作人员发送了“停止”操作。消息给。有没有办法让工作人员向服务器发回某种直接的amqp通道,服务器可以使用它来发送STOP消息?

1 个答案:

答案 0 :(得分:1)

最简单的答案似乎是工人要创建一个"回复"队列,并在' START_SUCCESS'中将该标识符发送到服务器消息,以及在某个地方声明的服务器存储。

然而,我认为RabbitMQ的大部分功能来自于这样的事实:消息不是直接发布到队列,而是发布到交换机,它们的最终目的地是由它们的路由密钥决定的。 (按队列名称发布实际上是通过使用路由密钥作为队列名称的交换。)如果您不熟悉不同类型的交换,请通读the RabbitMQ Getting Started tutorials

在这种情况下,您可以考虑发布和订阅彼此的更新,而不是考虑服务器和工作人员需要了解彼此的身份。如果所有内容都发布到交易所,那么服务器和工作人员实际上并不需要了解彼此的身份。

以下是我的工作方式:

  1. 服务器为特定作业生成唯一ID。
  2. 服务器向交换机jobs.new发布START消息,其中路由密钥对作业类型和消息中的作业ID进行分类。
  3. 服务器将匿名队列绑定到直接或主题交换jobs.status,绑定密钥设置为作业ID。
  4. 工作人员启动并从{{​​1}}(或jobs.ready)收到一条消息。
  5. 工作人员将匿名队列绑定到jobs.ready.some_type交换,并将作业ID作为绑定密钥。
  6. 工作人员启动任务,并以作业ID作为路由密钥向交换jobs.control发布START_SUCCESS消息。
  7. 服务器从步骤3绑定的队列接收START_SUCCESS消息,并更新该作业的状态。
  8. 工作人员定期向jobs.status交换机发送UPDATE消息;再次,路由密钥与作业ID匹配,因此服务器接收消息。
  9. 当服务器想要停止(或修改)正在运行的作业时,它会向作为路由密钥的作业ID的jobs.status交换发布STOP消息。
  10. 工作人员在步骤5绑定的队列上收到此消息,并停止作业。
  11. 从RabbitMQ方面来看,您有以下要素:

    • 3次交流:
      • jobs.control服务器发布新作业。如果所有工作人员都能处理所有工作,这可能是一个简单的扇出交换,或者它可能是一个主题交换,它将不同的工作队列路由到不同类型的工作人员。
      • jobs.new工作人员发布更新。这将是直接或主题交换,其路由键是或包含作业ID。
      • jobs.status服务器发布更新以控制现有作业。同样,这将是直接或主题交换,其路由键是或包含作业ID。
    • 永久排队:
      • 单个jobs.control队列或不同的jobs.ready队列绑定到jobs.ready.some_type交换。
    • 匿名队列:
      • 服务器创建的每个作业的一个队列,并使用该作业的ID绑定到jobs.new交换。或者,服务器进程可以为入站流量设置单个队列,只需从收到的消息中读取作业ID。
      • 每个工作人员创建一个队列,并使用其当前正在处理的作业的ID绑定到jobs.status交换。

    请注意,您可以将其他队列附加到这些交换中的任何一个以获取流量的副本,例如:用于记录或调试。对于主题交换,只需使用绑定密钥jobs.control绑定额外队列,它将获得所有消息的副本,而不会中断任何现有绑定。