RabbitMQ - 预定队列 - 死信队列 - 良好做法

时间:2014-06-15 03:24:36

标签: rabbitmq bunny

我们已经使用Rabbit设置了一些工作流环境。

它解决了我们的需求,但我想知道这样做是否也是好的做法,就像我们为计划任务所做的那样。

调度意味着没有任务关键的100%调整时间。因此,如果一个作业应该在60秒后重试,那么它确实意味着超过60秒,这取决于队列的处理时间。

我创建了一个Q_WAIT并制作了一些标题来传输设置。

让我们这样做:

工作人员正在Q_ACTION订阅

如果操作错过(例如smtp服务器无法访问)

- > (重新)将消息发布到Q_WAIT并设置properties.headers ["预定"] =时间+ 60秒


另一个进程循环每隔15秒通过方法pop()通过Q_WAIT中的所有消息而不是通过订阅

q_WAIT.pop(:ack => true) do |delivery_info,properties,body|...

  if (properties.headers["scheduled"] has reached its time)

     -> (Re-)Publish the message back to Q_ACTION
        ack(message)

在每个循环之后,连接关闭,因此NOT(Re-)Published保留在Q_WAIT中,因为它们未被确认。


有人可以证实这是一种有效的做法。

2 个答案:

答案 0 :(得分:3)

当然,您可以使用原始问题中描述的循环过程。

此外,您可以将Time-To-Live ExtensionDead Letter Exchanges extension一起使用。

首先,指定x-dead-letter-exchange Q_WAIT队列参数等于当前交换,x-dead-letter-routing-key等于Q_ACTION绑定的路由密钥。

然后在发布期间设置x-message-ttl队列参数集或设置消息expires属性,如果您需要自定义每消息ttl(尽管有一些well-known caveats这不是最佳实践,但它也有效)

在这种情况下,您的邮件将在他们的ttl到期后立即从Q_WAIT传递到Q_ACTION,而不会有任何额外的消费者,这更加可靠和稳定。

注意,如果您需要高级重新发布逻辑(更改邮件正文,属性),则需要使用其他队列(比如Q_PRE_ACTION)来使用消息,更改它们然后发布到目标队列(比如{{1 }})。

答案 1 :(得分:0)

正如评论中所提到的,我尝试了x-dead-letter-exchange的这个功能,它适用于大多数要求。一个问题/误解是TTL-PER-MESSAGE选项。

请看这里的例子。根据我的理解:

  1. DLQ的超时时间为10秒
  2. 因此,发布后10秒钟将在订阅者处提供第一条消息。
  3. 第二条消息在第一条消息发布1秒后发布,消息-ttt(有效期)为3秒
  4. 我希望第二条消息应该在发布3秒后和第一条消息之前宣布。

    但它没有这样的效果,两者都在10秒后可用。

    问:消息到期是否应该否决DLQ ttl?

    #!/usr/bin/env ruby
    # encoding: utf-8
    
    require 'bunny'
    
    B = Bunny.new ENV['CLOUDAMQP_URL']
    B.start
    
    DELAYED_QUEUE='work.later'
    DESTINATION_QUEUE='work.now'
    
    def publish
      ch = B.create_channel
      # declare a queue with the DELAYED_QUEUE name
      q = ch.queue(DELAYED_QUEUE, :durable => true, arguments: {
        # set the dead-letter exchange to the default queue
        'x-dead-letter-exchange' => '',
        # when the message expires, set change the routing key into the destination queue name
        'x-dead-letter-routing-key' => DESTINATION_QUEUE,
        # the time in milliseconds to keep the message in the queue
        'x-message-ttl' => 10000,
      })
      # publish to the default exchange with the the delayed queue name as routing key,
      # so that the message ends up in the newly declared delayed queue
      ch.basic_publish('message content 1 ' + Time.now.strftime("%H-%M-%S"), "", DELAYED_QUEUE, :persistent => true)
      puts "#{Time.now}: Published the message 1"
    
      # wait moment before next publish
      sleep 1.0
    
      # puts this with a shorter ttl
      ch.basic_publish('message content 2 ' + Time.now.strftime("%H-%M-%S"), "", DELAYED_QUEUE, :persistent => true, :expiration => "3000")
      puts "#{Time.now}: Published the message 2"
    
      ch.close
    end
    
    def subscribe
      ch = B.create_channel
      # declare the destination queue
      q = ch.queue DESTINATION_QUEUE, durable: true 
      q.subscribe do |delivery, headers, body|
        puts "#{Time.now}: Got the message: #{body}"
      end
    end
    
    subscribe()
    publish()
    
    sleep