AMQP: Basic.Publish immediate versus mandatory

I was unclear about the difference between the mandatory and immediate options for the AMQP Basic.Publish method, so I did a little investigation with Bunny and RabbitMQ.

It turns out that the difference is pretty straightforward. If you publish a message with the :mandatory option set to true like so –


my_exchange.publish('Test message', :mandatory => true)

Then your message will be returned unless it can be routed to a queue.

However, if you publish a message with the :immediate option set to true, as in this example –


my_exchange.publish('Test message', :immediate => true)

Then your message will be returned unless it can be consumed immediately.

IMPORTANT: If you use either of these options with Exchange#publish in Bunny, you must check whether or not your message has been returned after you make the publish call, otherwise return messages will build up and problems will ensue. With Bunny you can check for returned messages by placing something similar to the following after your publish call –


returned_msg = my_client.returned_message

The Client#returned_message method takes an optional :timeout argument (default value is 0.1 seconds). This allows you to specify how long the method will wait to receive a returned message should the default value prove to be problematic.

If there is a returned message the method returns a hash containing :header, :payload and :return_details. The payload contains the message contents. If there is no returned message the method returns the symbol :no_return.

5 thoughts on “AMQP: Basic.Publish immediate versus mandatory

  1. Pieter Hintjens

    Hey Chris,

    Mandatory and immediate are meant to let an application detect specific kinds of wiring problems. So the “mandatory” flag is used for SOAs where you expect a routing key to properly get resolved to some queue. I.e. the service is present and registered, as a binding on the exchange. This lets apps do things like “send to service A, and if that service does not exist, send an alert to service B”.

    The “immediate” flag is about whether the service is actually running properly or not, i.e. if the message can be delivered NOW, rather than being queued for later. This lets apps do things like “send to service A, and if that’s busy, send to service B instead”.

    In both cases to make any use of these flags you have to handle returned messages, as you said. The difference between the two options is subtle, and most apps will just say “mandatory & immediate” if they want either.

    HTH.

    Reply
  2. Simon MacMullen

    Then your message will be returned unless it can be consumed from a queue very quickly. I don’t know exactly how long the message can remain in the queue before it is returned, but it is necessarily a short time.

    The message needs to go straight out to a consumer – i.e. when it gets to the queue the queue must be of length 0 and there needs to be a non-blocked consumer it can be routed to. In such a circumstance we don’t consider the message ever to be in the queue (i.e. rabbitmqctl / management will always show length 0).

    So the message can’t be in the queue for even a nanosecond.

    Reply
  3. IAmFledge (Edward Woodcock)

    Thanks for this post, it helped out a lot. One comment is the end saying:

    “If there is no returned message the method returns the symbol :no_return.”

    This should be clarified a bit to say that :no_return comes under the payload. The method itself returns:
    {:header=>nil, :payload=>:no_return, :return_details=>nil}

    Ed.

    Reply

Leave a comment