Skip to content
Logo Theodo

Introduction to Event-driven Architectures With RabbitMQ

Nicolas Judalet10 min read

Event-driven architectures (EDA) gather several useful patterns to deliver maintainable code, handle asynchronous tasks and build reliable applications.

As a developer at Theodo, I have been working with various companies to help them build great products. I frequently used event-driven architectures along the way, and I want to share my thoughts with you on this subject.

This article is a conceptual overview of some characteristics of event-driven architectures. For a hands-on tutorial on how to implement your own EDA with RabbitMQ, my advice is to go see RabbitMQ excellent tutorials.

What is an event-driven architecture?

Though it looks basic, this question is quite tricky. I recommend a very good article on this subject, by Martin Fowler: “What do you mean by event-driven?” (if you prefer videos, Martin Fowler also presents the content of the article in the following conference). Some key takeaways from this article:

Each one of these patterns is of interest and deserve further reading! In the following parts of the article, we are going to present more in detail the Event Notification pattern.

Learning by example

We are going to illustrate the Event Notification pattern through an example. Let us pretend that I just bought a new item on an e-commerce website, also asking to save my credit card for further purchase.

When I click the “Buy” button, a payment request will be submitted, and hopefully will succeed. A payment success is a significant change in application state: in other words, an event (following Wikipedia’s definition). Following this event, the website should trigger several actions, for example:

Each one of these actions is independent of the others and must be carried out by different parts of the code: let us say different microservices (abbreviated MS later in this article), as represented in the figure below. 

So the question is: How to notify every MS on the right part of the figure that a “payment_succeeded” event occurred in the Payment MS?

How to implement event notification?

How to notify that the “payment_succeeded” event occurred?

We are going to present two different architectures for this task (spoiler: one of them is what we call the Event Notification pattern — will you guess which one ?): orchestration and choreography.

Event Notification: orchestration vs choreography

The distinction between orchestration and choreography is well captured by this quote by Sam Newman (taken from the very good book Building Microservices):

“With orchestration, we rely on a central brain to guide and drive the process, much like the conductor in an orchestra.

With choreography, we inform each part of the system of its job, and let it work out the details, like dancers all finding their way and reacting to others around them in a ballet”

Orchestration in action

In our example, the central brain would be the part of the code that senses the initial event, i.e. the Payment MS. He would then command hierarchically the other MS’s to carry out the required actions, by sending requests to endpoints specifically designed for this purpose. Therefore, this kind of architecture is called request-driven.

Request-driven architecture: orchestration pattern

Orchestration pattern (request-driven architecture)

1: The front app sends a request to the Payment MS, informing it that I, customer, clicked the “Buy” button (with the “Save my credit card” checkbox also toggled);

2: The Payment MS handles the request and the payment succeeds;

3, 4, 5: the Payment MS successively sends requests to the Order MS, Messenger MS, and Customer MS to command them to carry out required actions, resp. create a new order, send an order confirmation email, and save the credit card;

6: The Payment MS can finally send a response to the front app request, to load the confirmation page.

Choreography in action

As an alternative, choreography is a way more decoupled way to pass the information from the Payment MS to the others.

The Payment MS knows that a payment succeeded. But is it its responsibility to know the list of all the tasks that must be triggered following a successful payment? Not really. It is rather the responsibility of the Order MS to know what to do on its side when a payment succeeds. The same thing holds for the Messenger and Customer MS’s. And here comes the… Event Notification pattern, a.k.a. choreography! 🎉

Following this pattern, the Payment MS will just notify that a “payment_succeeded” event occurred, using a messaging system. The messaging system will then deliver this message to all the MS’s that need to take action. Each MS will finally consume the message and trigger the corresponding actions.

The interesting part is that the Payment MS does not need to know which actions will be triggered in other parts of the code following the event notification. This ensures a high level of decoupling between the MS’s.

Event-driven architecture: choreography pattern

Choreography pattern (event-driven architecture)

1: The front app sends a request to the Payment MS, informing it that I, customer, clicked the “Buy” button (with a “Save my credit card” checkbox also toggled);

2: The Payment MS handles the request and the payment succeeds;

3: The Payment MS publishes a message “payment_succeeded” in a messaging system;

4: The Order, Messenger and Customer MS’s are notified asynchronously that the event occurred by receiving the message (= the “event notification”). In parallel, the Payment MS can directly send the response to the front app, without waiting for the three MS’s to carry out their tasks.

Diving into the Messaging System: RabbitMQ Concepts

The central element of the Event Notification pattern is the messaging system.

Several solutions exist to handle messages: we will not answer the question “How to choose your messaging system” in this article, but if you want some input on this question, the most used solutions as for today are: RabbitMQ, Kafka, or Amazon SQS. Here is also a story on a development team who tells how they made their choice. The one I know better is RabbitMQ, so let me give you a brief overview of how it works.

RabbitMQ follows a protocol called AMQP (Advanced Message Queueing Protocol), which defines a standard way for systems to communicate through messages. The main concepts are the following ones:

For a more detailed presentation of the inner working of RabbitMQ and other AMQP-compliant messaging systems, you can go have a look at this very good article!

Event notification implementation with RabbitMQ

Now that we know the basic concepts of RabbitMQ, let me show you how we implemented them in our previous example.

RabbitMQ configuration

The following figure describes how you can configure RabbitMQ:

Configure exchanges, bindings and queues on RabbitMQ

Publishing and consuming messages

Finally, here is the full picture:

Publish and consume messages
with RabbitMQ

  1. The Payment MS publishes a new message with the routing key “payment_succeeded” on the “ms.payment” exchange;
  2. Thanks to the bindings we declared between the exchange and the queues, 3 copies of the message are created and distributed to the queues;
  3. Consumers that registered to the queues get their copy of the message and trigger the execution of the task they must carry out.

Quite simple, isn’t it?

Final thoughts: advantages and limits of Event Notification

In conclusion, when should we implement the Event Notification pattern? Let me wrap some pros and cons to help you determine if your use case is a good candidate for it:

Pros

Cons

I hope this article was clear and useful for you, and that you will enjoy writing nice code using events in your app! Please leave comments if you have questions or remarks.

Want to use Event-Driven Architecture on your project back-end? Feel free to contact one of your Python back-end experts!

Liked this article?