This guide covers bindings in AMQP 0.9.1, what they are, what role they play and how to accomplish typical operations using the Ruby amqp gem.
This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images and stylesheets). The source is available on Github.
This guide covers Ruby amqp gem 1.7.0 and later.
Learn more about how bindings fit into the AMQP Model in the AMQP 0.9.1 Model Explained documentation guide.
Bindings are rules that exchanges use (among other things) to route messages to queues. To instruct an exchange E to route messages to a queue Q, Q has to be bound to E. Bindings may have an optional routing key attribute used by some exchange types. The purpose of the routing key is to selectively match only specific (matching) messages published to an exchange to the bound queue. In other words, the routing key acts like a filter.
To draw an analogy:
Some exchange types use routing keys while some others do not (routing messages unconditionally or based on message metadata). If an AMQP message cannot be routed to any queue (for example, because there are no bindings for the exchange it was published to), it is either dropped or returned to the publisher, depending on the message attributes that the publisher has set.
If an application wants to connect a queue to an exchange, it needs to bind them. The opposite operation is called unbinding.
In order to receive messages, a queue needs to be bound to at least one exchange. Most of the time binding is explcit (done by applications). To bind a queue to an exchange, use { yard_link AMQP::Queue#bind } where the argument passed can be either an { yard_link AMQP::Exchange } instance or a string.
queue.bind(exchange) do |bind_ok|
puts "Just bound #{queue.name} to #{exchange.name}"
end
#!/usr/bin/env ruby
# encoding: utf-8
require "rubygems"
require "amqp"
# Binding a queue to an exchange
AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok|
channel = AMQP::Channel.new(connection)
exchange = channel.fanout("amq.fanout")
channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok|
queue.bind(exchange) do |bind_ok|
puts "Just bound #{queue.name} to #{exchange.name}"
end
connection.close {
EventMachine.stop { exit }
}
end
end
The same example using a string without a callback:
queue.bind("amq.fanout")
#!/usr/bin/env ruby
# encoding: utf-8
require "rubygems"
require "amqp"
# Binding a queue to an exchange
AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok|
channel = AMQP::Channel.new(connection)
exchange_name = "amq.fanout"
channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok|
queue.bind(exchange_name)
puts "Bound #{queue.name} to #{exchange_name}"
connection.close {
EventMachine.stop { exit }
}
end
end
To unbind a queue from an exchange use
AMQP::Queue\#unbind
:
queue.unbind(exchange)
#!/usr/bin/env ruby
# encoding: utf-8
require "rubygems"
require "amqp"
AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok|
channel = AMQP::Channel.new(connection)
channel.on_error do |ch, channel_close|
raise "Channel-level exception: #{channel_close.reply_text}"
end
exchange = channel.fanout("amq.fanout")
channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok|
queue.bind(exchange)
EventMachine.add_timer(0.5) do
queue.unbind(exchange) do |_|
puts "Unbound. Shutting down..."
connection.close { EventMachine.stop }
end
end # EventMachine.add_timer
end # channel.queue
end
Trying to unbind a queue from an exchange that the queue was never bound to will result in a channel-level exception.
After an AMQP message reaches an AMQP broker and before it reaches a consumer, several things happen:
A more in-depth description is this:
The important thing to take away from this is that messages may or may not be routed and it is important for applications to handle unroutable messages.
Unroutable messages are either dropped or returned to producers. Vendor-specific extensions can provide additional ways of handling unroutable messages: for example, RabbitMQ’s Alternate Exchanges extension makes it possible to route unroutable messages to another exchange. amqp gem support for it is documented in the Vendor-specific Extensions guide.
The amqp gem provides a way to handle returned messages with the
AMQP::Exchange#on_return
method:
exchange.on_return do |basic_return, metadata, payload|
puts "#{payload} was returned! reply_code = #{basic_return.reply_code}, reply_text = #{basic_return.reply_text}"
end
Working With Exchanges documentation guide provides more information on the subject, including full code examples.