Quick intro to RabbitMQ

RabbitMQ is an example of full blown Message Queue that somehow remained simple to use. Unlike ZeroMQ, which is embeddable into the services that use it, RabbitMQ is a broker. It’s an intermediary messaging service with own users, permissions, encryption, configurable durability and delivery acknowledgements, clustering, high availability, and bazillion of other features you might never need. RabbitMQ is built on top of Erlang and inherits its known resilience with compatibility to virtually any OS.

In the following article we’ll try to get a sense of how messaging with RabbitMQ feels like. I’ve chosen Ubuntu (in a Docker container) as a platform, but it could’ve been anything else.

Installation

Installation is not in the focus here, especially when official documentation is so good, but the simplest method of getting it up and running is through rabbitmq Docker container.

This will get you fully configured RabbitMQ server, which only waits to be started:

If you’re not familiar with Docker, installing RabbitMQ on real machine is also not that hard. This is how it looks for Ubuntu:

It won’t be harder on other systems, but I’d highly recommend investing some time in learning Docker, as it’s an amazing tool for experimenting with such kind of stuff. Just pull the image of already configured software (RabbitMQ, Redis, Elasticsearch, Jenkins, and ton of others), play with it and throw away when you’ve done. That’s brilliant.

Sending and receiving messages with rabbitmqadmin

You don’t have to write any code to start sending and receiving messages. RabbitMQ comes with management plugin which has rabbitmqadmin  – a tool capable of creating message queues, sending messages, querying queue status, etc. Management plugin is disabled by default, so let’s enable it first.

Getting rabbitmqadmin ready

..and it’s done. It also worth adding rabbitmqadmin location to PATH variable, or at least creating a link to it in /usr/local/bin/.

Cool! Now we can do something with it.

Messing with queues and messages

RabbitMQ is a broker that hosts message queues and in your average distributed application it sits somewhere in the middle:

Asynchronous communication

First, let’s see what queues it has by default:

Not much. But it’s something we can easily fix:

We created a queue called “demoqueue” which is not durable, so as soon as RabbitMQ server shuts down, all non-delivered messages will be lost. Talking about the messages, let’s create one!

Send message command looked more complicated than it should, so I think I owe you some explanations.

AMQP detour

There’s emerging standard for message queue protocols called AMQP (Advanced Message Queuing Protocol). According to this standard, there should be one more actor between message publisher and message queue called exchange. It’s like a mailbox – before your letter gets to the post office, it should hang in somewhere for a while. Publisher sends the message to exchange, while exchange’s type and its bindings define where it goes next.

For example, if exchange type is “fanout” (one of predefined types), then every message that hits the exchange will be broadcasted to all message queues bound to it.

On the other hand, there’s “direct” exchange, which routes messages by certain routing key. It’s like “OK, exchange, here’s message queue X I bind to you. Whenever you get a message with routing key Y, forward it to X”.

RabbitMQ conforms AMQP standard, so it also comes with predefined amq.default exchange, which is, in fact, “direct”-type exchange that every MQ is automatically bound to, using their name as a routing key. So this line probably makes more sense now:

Finally, let’s receive (“consume” in RabbitMQ terminology) that message back:

requeue=true  argument indicates that message should be put back into the queue after it’s read, so we can play with it later.

Sending and receiving messages with NodeJS

So we’ve learned that RabbitMQ is a message broker we can send to and receive messages from via command line tools. How sweet. I wonder how hard it’s to do that programmatically. Spoiler – not hard at all.

I’ve chosen JavaScript and NodeJS for the demo, as this is the quickest way for me to get it up and running, but any language with AMQP library would do.

NPM has a package called amqplib and that’s exactly what we need:

Before we could send or receive messages, we need to connect to RabbitMQ server and open a channel:

amqplib comes with Promise API, but they have callback-style syntax as well. What’s more, it also allows publishing messages directly to MQs, bypassing exchange – feature I’m going to exploit in a few seconds.

Now, having connection established, let’s make sure the queue we’re going to publish to actually exists:

The beauty of assertQueue is that if queue doesn’t exist, it will be created. Finally, channel is ready, queue is ready – time to send something:

And… that’s it. That code is enough to create MQ and send message to it using AMQ Protocol.

NodeJS program for reading from queue is almost identical to one that sends it:

We could’ve add {noAck: false} parameter to consume method, so messages wouldn’t be acknowledged as read and therefore would stay in the queue (like reading with rabbitmqadmin and requeue=true flag), but that’s too much for one day.

Summary

In this article we barely scratched the surface of what RabbitMQ can. In fact, none of the features I mentioned in the beginning were used. But the point I was trying to make is that being a feature rich tool that is capable of handling extremely complex scenarios doesn’t mean it also should be hard to use. In contrary, examples above were quite trivial.

But it’s a shame to use such a tool for hello-world applications. Let’s try something more complex next time.

2 thoughts on “Quick intro to RabbitMQ

Leave a Reply

Your email address will not be published. Required fields are marked *