August 29, 2019Nicolas Judalet9 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.
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.
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 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.
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”
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.
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.
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.
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.
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!
Now that we know the basic concepts of RabbitMQ, let me show you how we implemented them in our previous example.
The following figure describes how you can configure RabbitMQ:
Finally, here is the full picture:
Quite simple, isn’t it?
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:
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!
Web Developer at Theodo