-
Introduction
RabbitMQ is a message broker. The principal idea is pretty simple: it accepts and forwards messages.
RabbitMQ, and messaging in general, uses some jargon.
-
Producing means nothing more than sending. A program that sends messages is a producer. We'll draw it like that, with "P":
-
A queue is the name for a mailbox. It lives inside RabbitMQ. Although messages flow through RabbitMQ and your applications, they can be stored only inside a queue. A queue is not bound by any limits, it can store as many messages as you like ‒ it's essentially an infinite buffer. Many producers can send messages that go to one queue, many consumers can try to receive data from one queue. A queue will be drawn as like that, with its name above it:
-
Consuming has a similar meaning to receiving. A consumer is a program that mostly waits to receive messages. On our drawings it's shown with "C":
Note that the producer, consumer, and broker do not have to reside on the same machine; indeed in most applications they don't.
Hello World!
(using the pika 0.9.8 Python client)
Our "Hello world" won't be too complex ‒ let's send a message, receive it and print it on the screen. To do so we need two programs: one that sends a message and one that receives and prints it.
Our overall design will look like:
Producer sends messages to the "hello" queue. The consumer receives messages from that queue.
-
-
Sending
Our first program send.py will send a single message to the queue. The first thing we need to do is to establish a connection with RabbitMQ server.
1 #!/usr/bin/env python 2 import pika 3 4 connection = pika.BlockingConnection(pika.ConnectionParameters( 5 'localhost')) 6 channel = connection.channel()
We're connected now, to a broker on the local machine - hence the localhost. If we wanted to connect to a broker on a different machine we'd simply specify its name or IP address here.
Next, before sending we need to make sure the recipient queue exists. If we send a message to non-existing location, RabbitMQ will just trash the message. Let's create a queue to which the message will be delivered, let's name it hello:
1 channel.queue_declare(queue='hello')
At that point we're ready to send a message. Our first message will just contain a string Hello World! and we want to send it to our hello queue.
In RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange. But let's not get dragged down by the details ‒ you can read more aboutexchanges in the third part of this tutorial. All we need to know now is how to use a default exchange identified by an empty string. This exchange is special ‒ it allows us to specify exactly to which queue the message should go. The queue name needs to be specified in the routing_key parameter:
1 channel.basic_publish(exchange='', 2 routing_key='hello', 3 body='Hello World!') 4 print " [x] Sent 'Hello World!'"
Before exiting the program we need to make sure the network buffers were flushed and our message was actually delivered to RabbitMQ. We can do it by gently closing the connection.
1 connection.close()
Receiving
Our second program receive.py will receive messages from the queue and print them on the screen.
Again, first we need to connect to RabbitMQ server. The code responsible for connecting to Rabbit is the same as previously.
The next step, just like before, is to make sure that the queue exists. Creating a queue using queue_declare is idempotent ‒ we can run the command as many times as we like, and only one will be created.
1 channel.queue_declare(queue='hello')
Receiving messages from the queue is more complex. It works by subscribing a callback function to a queue. Whenever we receive a message, this callback function is called by the Pika library. In our case this function will print on the screen the contents of the message.
1 def callback(ch, method, properties, body): 2 print " [x] Received %r" % (body,)
Next, we need to tell RabbitMQ that this particular callback function should receive messages from our hello queue:
1 channel.basic_consume(callback, 2 queue='hello', 3 no_ack=True)
For that command to succeed we must be sure that a queue which we want to subscribe to exists. Fortunately we're confident about that ‒ we've created a queue above ‒ usingqueue_declare.
The no_ack parameter will be described later on.And finally, we enter a never-ending loop that waits for data and runs callbacks whenever necessary.
-
1 print ' [*] Waiting for messages. To exit press CTRL+C' 2 channel.start_consuming()
Putting it all together
Full code for send.py:
1 #!/usr/bin/env python 2 import pika 3 4 connection = pika.BlockingConnection(pika.ConnectionParameters( 5 host='localhost')) 6 channel = connection.channel() 7 8 channel.queue_declare(queue='hello') 9 10 channel.basic_publish(exchange='', 11 routing_key='hello', 12 body='Hello World!') 13 print " [x] Sent 'Hello World!'" 14 connection.close()
Full receive.py code:
1 #!/usr/bin/env python 2 import pika 3 4 connection = pika.BlockingConnection(pika.ConnectionParameters( 5 host='localhost')) 6 channel = connection.channel() 7 8 channel.queue_declare(queue='hello') 9 10 print ' [*] Waiting for messages. To exit press CTRL+C' 11 12 def callback(ch, method, properties, body): 13 print " [x] Received %r" % (body,) 14 15 channel.basic_consume(callback, 16 queue='hello', 17 no_ack=True) 18 19 channel.start_consuming()