For RPM-based distributions like RedHat or CentOS, the RabbitMQ team
provides an RPM package.

Note: The RabbitMQ
package that ships with some popular Ubuntu versions (for example,
10.04 and 10.10) is outdated and *will not work with amqp gem 0.8.0
and later versions* (you will need at least RabbitMQ v2.0 for use with
this guide).

This example demonstrates a very common communication scenario: application A wants to publish a message that will end up in a queue that application B listens on. In this case, the queue name is "amqpgem.examples.hello". Let us go through the code step by step:

require"rubygems"require"amqp"

is the simplest way to load the amqp gem if you have installed it with RubyGems, but remember that you can omit the rubygems line if your environment does not need it. The following piece of code

EventMachine.rundo# ...end

runs what is called the EventMachine
reactor. We will not go into what the term 'reactor' means here, but
suffice it to say that the amqp gem is asynchronous and is based on an
asynchronous network I/O library called EventMachine.

The next line

connection=AMQP.connect(:host=>'127.0.0.1')

connects to the server running on localhost, with the default port (5672), username (guest), password (guest) and virtual host ('/').

The next line

channel=AMQP::Channel.new(connection)

opens a new channel. AMQP is a multi-channeled protocol that uses channels to multiplex a TCP connection.

Channels are opened on a connection, therefore the AMQP::Channel constructor takes a connection object as a parameter.

This line

queue=channel.queue("amqpgem.examples.helloworld",:auto_delete=>true)

declares a queue on the channel that we have just opened. Consumer applications get messages from queues. We declared this queue with the "auto-delete" parameter. Basically, this means that the queue will be deleted when there are no more processes consuming messages from it.

The next line

exchange=channel.direct("")

instantiates an exchange. Exchanges receive messages that are sent
by producers. Exchanges route messages to queues according to rules
called bindings. In this particular example, there are no explicitly
defined bindings. The exchange that we defined is known as the
default exchange and it has implied bindings to all queues. Before
we get into that, let us see how we define a handler for incoming
messages

AMQP::Queue#subscribe takes a block that will be called every time a message arrives. AMQP::Session#close closes the AMQP connection and runs a callback that stops the EventMachine reactor.

Finally, we publish our message

exchange.publish"Hello, world!",:routing_key=>queue.name

Routing key is one of the message attributes. The default exchange
will route the message to a queue that has the same name as the
message's routing key. This is how our message ends up in the
"amqpgem.examples.helloworld" queue.

This first example can be modified to use the method chaining technique:

For the sake of simplicity, both the message producer (App I) and the
consumer (App II) are running in the same Ruby process. Now let us
move on to a little bit more sophisticated example.

Blabblr: one-to-many publish/subscribe (pubsub) example

The previous example demonstrated how a connection to a broker is made and how to do 1:1 communication using the default exchange. Now let us take a look at another common scenario: broadcast, or multiple consumers and one producer.

A very well-known broadcast example is Twitter: every time a person
tweets, followers receive a notification. Blabbr, our imaginary
information network, models this scenario: every network member has a
separate queue and publishes blabs to a separate exchange. Three
Blabbr members, Joe, Aaron and Bob, follow the official NBA account on
Blabbr to get updates about what is happening in the world of
basketball. Here is the code:

The first line has a few differences from the "Hello, world" example above:

We use AMQP.start instead of AMQP.connect

Instead of return values, we pass a block to the connection method and it yields a connection
object back as soon as the connection is established.

Instead of passing connection parameters as a hash, we use a URI string.

AMQP.start is just a convenient way to do

EventMachine.rundoAMQP.connect(options)do|connection|# ...endend

The AMQP.start call blocks the current thread which
means that its use is limited to scripts and small command line
applications. Blabbr is just that.

AMQP.connect, when invoked with a block, will yield a
connection object as soon as the AMQP connection is open. Finally,
connection parameters may be supplied as a Hash or as a connection
string. The AMQP.connect method documentation contains all of the
details.

In this example, opening a channel is no different to opening a
channel in the previous example, however, the exchange is declared
differently

exchange=channel.fanout("nba.scores")

The exchange that we declare above using AMQP::Channel#fanout is a fanout exchange. A fanout exchange delivers messages to all of the queues that are bound to it: exactly what we want in the case of Blabbr!

is similar to the subscription code that we used for message delivery previously, but what does that AMQP::Queue#bind method do? It sets up a binding between the queue and the exchange that you pass to it. We need to do this to make sure that our fanout exchange routes messages to the queues of any subscribed followers.

exchange.publish("BOS 101, NYK 89").publish("ORL 85, ALT 88")

demonstrates AMQP::Exchange#publish call chaining. Blabbr members use a fanout exchange for publishing, so there is no need to specify a message routing key because every queue that is bound to the exchange will get its own copy of all messages, regardless of the queue name and routing key used.

The code that we want to run deletes the exchange that we declared earlier using AMQP::Exchange#delete and closes the AMQP connection with AMQP::Session#close. Finally, we stop the EventMachine event loop and exit.

Blabbr is pretty unlikely to secure hundreds of millions of dollars in funding, but it does a pretty good job of demonstrating how one can use AMQP fanout exchanges to do broadcasting.

Weathr: many-to-many topic routing example

So far, we have seen point-to-point communication and broadcasting. Those two communication styles are possible with many protocols, for instance, HTTP handles these scenarios just fine. You may ask "what differentiates AMQP?" Well, next we are going to introduce you to topic exchanges and routing with patterns, one of the features that makes AMQP very powerful.

Our third example involves weather condition updates. What makes it different from the previous two examples is that not all of the consumers are interested in all of the messages. People who live in Portland usually do not care about the weather in Hong Kong (unless they are visiting soon). They are much more interested in weather conditions around Portland, possibly all of Oregon and sometimes a few neighbouring states.

Our example features multiple consumer applications monitoring updates for different regions. Some are interested in updates for a specific city, others for a specific state and so on, all the way up to continents. Updates may overlap so that an update for San Diego, CA appears as an update for California, but also should show up on the North America updates list.

We use a topic exchange here. Topic exchanges are used for multicast messaging where consumers indicate which topics they are interested in (think of it as subscribing to a feed for an individual tag in your favourite blog as opposed to the full feed). Routing with a topic exchange is done by specifying a routing pattern on binding, for example:

channel.queue("americas.south").bind(exchange,:routing_key=>"americas.south.#").subscribedo|headers,payload|puts"An update for South America: #{payload}, routing key is #{headers.routing_key}"end

Here we bind a queue with the name of "americas.south" to the topic exchange declared earlier using the AMQP::Queue#bind method. This means that only messages with a routing key matching "americas.south.#" will be routed to that queue. A routing pattern consists of several words separated by dots, in a similar way to URI path segments joined by slashes. Here are a few examples:

asia.southeast.thailand.bangkok

sports.basketball

usa.nasdaq.aapl

tasks.search.indexing.accounts

Now let us take a look at a few routing keys that match the "americas.south.#" pattern:

americas.south

americas.south.*brazil*

americas.south.*brazil.saopaolo*

americas.south.*chile.santiago*

In other words, the "#" part of the pattern matches 0 or more words.

For a pattern like "americas.south.*", some matching routing keys would be:

americas.south.*brazil*

americas.south.*chile*

americas.south.*peru*

but not

americas.south

americas.south.chile.santiago

so "*" only matches a single word. The AMQP 0.9.1 specification says that topic segments (words) may contain the letters A-Z and a-z and digits 0-9.

One more thing that is different from previous examples is that the block we pass to AMQP::Queue#subscribe now takes two arguments: a header and a body (often called the payload). Long story short, the header parameter lets you access metadata associated with the message. Some examples of message metadata attributes are:

message content type

message content encoding

message priority

message expiration time

message identifier

reply to (specifies which message this is a reply to)

application id (identifier of the application that produced the message)

and so on.

As the following binding demonstrates, "#" and "*" can also appear at the beginning of routing patterns:

For this example the publishing of messages is no different from that of previous examples. If we were to run the program, a message published with a routing key of "americas.north.us.ca.berkeley" would be routed to 2 queues: "us.california" and the server-named queue that we declared by passing a blank string as the name:

channel.queue("",:exclusive=>true)do|queue|queue.bind(exchange,:routing_key=>"americas.north.#").subscribedo|headers,payload|puts"An update for North America: #{payload}, routing key is #{headers.routing_key}"endend

The name of the server-named queue is generated by the broker and sent
back to the client with a queue declaration confirmation. Because the
queue name is not known before the reply arrives, we pass
AMQP::Channel#queue a callback and it yields us back a queue object
once confirmation has arrived.

Avoid race conditions

A word of warning: you may find examples on the Web of AMQP::Channel#queue usage that do not use callbacks. We recommend
that you use a callback for server-named queues, otherwise your code
may be subject to race
conditions. Even though
the amqp gem tries to be reasonably smart and protect you from most
common problems (for example, binding operations will be delayed until
after queue name is received from the broker), there is no way it can
do so for every case. The primary reason for supporting AMQP::Channel#queue usage without a callback for server-µnamed
queues is backwards compatibility with earlier versions of the gem.

Integration with objects

Since Ruby is a genuine object-oriented language, it is important to demonstrate how the Ruby amqp gem can be integrated into rich object-oriented code.

The AMQP::Queue#subscribe callback does not have to be
a block. It can be any Ruby object that responds to call. A common
technique is to combine
Object#method
and
Method#to_proc
and use object methods as message handlers.

Wrapping up

This is the end of the tutorial. Congratulations! You have learned quite a bit about both AMQP 0.9.1 and the amqp gem. This is only the tip of the iceberg. AMQP has many more features built into the protocol:

Reliable delivery of messages

Message confirmations (a way to tell broker that a message was or was not processed successfully)

What to read next

We recommend that you read the following guides next, if possible, in this order:

AMQP 0.9.1 Model Explained. A simple 2 page long introduction to the AMQP Model concepts and features. Understanding the AMQP Model
will make a lot of other documentation, both for the Ruby amqp gem and RabbitMQ itself, easier to follow. With this guide, you don't have to waste hours of time reading the whole specification.

Connection to the broker. This guide explains how to connect to an AMQP broker and how to integrate the amqp gem into standalone and Web applications.