Async Flow and RabbitMQ Exchange Types
The technology is improving day by day and necessities are changing. Old idle systems can not keep up with the change are outdated. Lightweight systems and applications are becoming the reason for preference.
In the past, we would create an application and write all requirements in a monolith way. After a while, managing the entire process with a single application started to bring a heavy load due to infrastructure, coding, various software or hardware dependencies, business complexity, and maintenance difficulties. Lots of methods have been tried in order to use the systems more effectively and they are still being developed.
After the division of businesses into domains, the load began to be distributed and more independent asynchronous processes emerged. It brought advantages such as making it simpler, easy to maintain, high performance, scalable, language, and environment independent applications.
Let’s continue with an example.
We have an API application and the client is calling it.
The user is waiting for the process to finish during the whole process.
This has happened to all of us. If the service response is late, we begin to consider whether the request has been received. It will cause a bad user experience. Wouldn’t it be enough if we only returned the information that the user needs at the moment and informed that the request is received and processed? If we run our works in parallel in the background, we will reduce the response time and use system resources more efficiently for other users in this process.
At this point, message brokers emerged and one of them is RabbitMQ.
We can think of RabbitMQ as a post office. It accepts the messages, stores them in a queue structure until they are received by the relevant application and forwards them in order. It uses the First in First Out method.
It provides reliability, flexible routing, highly available queues, many client providers for any language, UI management, tracing, good documentation.
One of its talents is to parallelize tasks easily. It uses the Round Robin algorithm and can distribute the messages according to the load distribution.
Let me briefly talk about the basic components of RabbitMQ.
- A Producer is an application that sends messages by user activities.
- An Exchange routes messages to related queues. Exchange and queues must be connected to each other with binding keys.
- A Queue stores messages.
- A Consumer is an application that receives messages.
RabbitMQ Message Flow
- The Producer publishes message to the Exchange.
- The Exchange receives the message and decides to forward it. Then the message is forwarded to the Queue.
- The message waits in the Queue until it is handled by the Consumer.
- The Consumer handles the message.
RabbitMQ has another member called Routing Key that provides great flexibility to the user. The routing key is part of the message. When the message is forwarded to the exchange, the exchange checks the routing key while deciding where to forward the message.
I mentioned that there is a binding key between the exchange and the queue. If the routing key of the sent message is compatible with the binding key, the corresponding queue or queues will receive the message. The concept will become more meaningful with the following examples.
Many articles can be written about RabbitMQ’s architectural design, flexible structure, advantages and services. However, in this section, I will talk about Exchange Types and give you a lot of examples about these.
RabbitMQ provides four types of exchanges: Fanout, Direct, Topic, and Headers.
It distributes these messages indiscriminately to all queues that bind to the Exchange. Fanout is suitable for broadcasting and the routing key is ignored even if there is.
Let’s imagine we have an e-commerce application that people of all ages use. We want a common message to be sent to users of all age groups without any discrimination. For example, it may be related to the start time of the big discount campaign.
In the new message section of the producer;
The first blank is reserved for the text of the message.
The second blank is for the routing key.
The last one determines the repeating time but it’s not necessary for us.
In our example, we are creating a message through the producer. Even if we pass “customer.group.children” as the routing key, the routing key is ignored and all queues received the message.
Routing key is a short generated string. The direct exchange routes to exactly matching queue or queues.
In the above example, we want to send messages only to users whose age group is “customer.group.children”. We specified “customer.group.children” as the routing key, therefore the children consumer received the message.
The exchange can be bound to different queues with the same binding key.
You can also bind more than one consumers to the same queue. Thus, you can scale your applications easily.
Message is sent to queues that match the routing key fully or partially. Topic has a structure separated by dot. It can be designed with patterns to be written specifically for the situation needed. It has a flexible structure.
There are also special characters such as *, #.
Asterisk (“*”) is used to match a word in a specific position of the routing key.
Pound symbol (#) is used to match zero or more words.
Routing depends on message headers. It is kept as a key value.
It has also an argument called “x-match”. “x-match” can have 2 types of values. “all” and “any”. The default value is “all”. “all” expects exactly matching. “any” is used when a header value being equal is sufficient.
Header keys; aged_group, gender, x-match.
For example, we want to send messages to middle-aged and male users.
For queue 1; x-match: all. We can expect that the message will reach to users that are “aged_group: middle-aged and gender: man”. It received.
For queue 2–3; x-match: any. We can expect that the message will reach to users that are “aged_group: middle-aged or gender: man”. They received.
For queue 4; x-match: all, and exact match could not be found. It couldn’t reach the message.
I hope that you enjoy it!