RabbitMq message broker for messenger development. Tips for developers

rabbitmg for developing messengers RabbitMq message broker for messenger development. Tips for developers

Development of mobile messengers have been increasingly gaining popularity recently. At the moment, there are plenty of mobile messengers, such as Viber, WhatsApp, or Telegram, each having its pros and cons.

Such applications have to be able to support heavy loads and be easily scalable which creates certain challenges for developers. That’s why we recommend integrating ready and reliable messaging platforms in such solutions. Such integration will help to transfer the solution to scalability problem to the messaging platform side and allow to pay more attention to new functionality development.

One of the platforms that is a good fit for messenger development is message broker RabbitMQ which supports different messaging protocols, such as AMQP, MQTT, STOMP, etc.

RabbitMQ has a large number of client libraries that allow it to be integrated with almost any client application platform.

In this article we’ll write about implementation of message transfer and processing using RabbitMQ.

First up, let’s get acquainted with this message broker’s specific working principle and terms.

RabbitMQ has the following components:

  • producer – client that creates message
  • consumer – client that receives message
  • queue – unlimited queue that stores messages
  • exchange – component allowing to route messages sent to it to different queues.

 

Generally, interaction of the components within RabbitMq is the following: producer sends a message to exchange, then exchange receives the message and routes it to queues subscribed to it. Depending on the type of exchange messages can be filtered based on correspondence of keys with which the queue is connected to the exchange and the keys in the message or routed to all interested queues, after which the consumer receives messages from the queue he/she is subscribed to.

Exchange can have one of a few possible types.

Types of exchange:

  • fanout – routes messages sent to it to all connected queues
  • direct – routes messages sent to it to connected queues according to filtration settings using routeld (can be one word)
  • topic – routes messages sent to it to connected queues according to filtration settings with using  routeld consisting of a few words which allows to achieve more flexible filtering.

 

This knowledge will be enough for further understanding of the article. Let’s move on to the architecture of the implemented system.

In general, a messenger developed using RabbitMq will have the following scheme.

RabbitMQ messenger

As it’s shown on the scheme, the system consists of the following parts:

  • RabbitMQ
  • Backend application
  • Client applications: Android, iOS

 

For the architecture to function one needs already set up exchanges and queues created at the first start of the backend application.

Here is the list of principal exchanges and queues:

  • “conversation.outgoing” is an exchange, type fanout, which in our case is required for receiving incoming messages from clients and routing them to the queues.
  • “conversation.incoming” is an exchange, type topic, for sending already processed messages to exchange of certain users. In our case topic type allows to send only those messages to users that relate to dialogues they participate in.
  • “chat-application-messages” is a queue for processing incoming messages by backend application.

 

After initialization all used exchanges and queues we connect exchangeconversation.outgoing” with queue chat-application-messages” and create backend message processor  from queuechat-application-messages”.

Integration of all parts of the system starts with user registration functionality.

When a user registers on the server using one of the clients (iOS, Android), a backend application creates exchange of fanout type in RabbitMQ with unique generated name and returns this exchange name to the client application in which the user registered.  

From then all authorised clients will also receive the name of this already existing exchange.

After receiving the exchange name of this user, the clients create a temporary queue in RabbitMQ, which exists only during the connection of the client with RabbitMQ message broker, and connect it with this exchange.

Creating one unique exchange for each user allows to receive messages on all clients (iOS, Android) at the same time.

After turning off the Internet on the client or in any other case when connection with RabbitMQ message broker is lost, a temporary queue will be automatically deleted on the server by RabbitMQ, thus preventing redundant messaging and optimizing our delivery. With a new connection a new queue will be created.

After registration, the user is ready for sending and receiving messages.

Sending messages takes place within dialogues. The system must allow to create conversations with both one and several contacts.

When creating a conversation, exchange of each user connects with exchange of the backend application “conversation.incoming”, using conversation id as routeId.

A general sequence of message delivery is shown on the picture.

RabbitMQ delivery scheme

Now let’s clarify the sequence of message delivery a bit. Incoming messages go to “conversation.outgoing” exchange which sends them to “chat-application-messages” queue. The backend application processes all messages sent to “chat-application-messages” queue.

When checking the message, the validity of user token, conversation id and the possibility of this user to send messages to this conversation are checked, attachment which has to be sent with the message is processed, and the message is stored in the backend application database and then sent to “conversation.incoming” exchange with conversation id as routeId.

“conversation.incoming” exchange will send the message to all exchanges that are signed with the same routeld as the sent message.

Filtration of the sent messages in RabbitMQ allows to conveniently scale the number of contacts receiving messages without increasing time for message delivery.

Exchange of a certain user will then transmits the message to all queues signed to this exchange, that is to all client applications.

Thus, if you need to develop a messenger app, the objective of message delivery with support of multi-user conversations and lots of clients used at the same time will be solved using RabbitMQ only and writing minimum code for the backend application.

 

The backend application (Android)

Considering that messengers imply quick communication, the possibility to receive new messages at any time and in any condition (online/offline) is necessary for the client application.

For ceaseless message receiving, in our Android app we implemented a background system service which constantly checks the queue we created for new messages.  

For implementation of this functionality on Android platform we use class that implements the standard Android IntentService.

At the start of the service it creates connection with RabbitMQ server and a temporary queue which it connects with exchange received from the backend application.

 

connection = ChatApplication.getApp().getRabbitMQConnectionFactory().newConnection();

channel = connection.createChannel();

queueName = channel.queueDeclare().getQueue();

channel.queueBind(queueName, ChatApp.getApp().getAppConfig().getExchangeName(), “#”);

 

From this moment the client is ready for receiving new messages. The code of receiving and processing messages is shown below.

 

QueueingConsumer consumer = new QueueingConsumer(channel);

channel.basicConsume(queueName, true, consumer);

while (true) {

  QueueingConsumer.Delivery delivery = consumer.nextDelivery();

  handleMessage(delivery);

}

 

handleMessage method has a code for messages processing, adding them to the local client base and displaying them on the UI.

For message delivery, Android application creates new connection with RabbitMQ and sends the message in json format to “conversation.outgoing” exchange.

 

Connection connection = СhatApp.getApp().getRabbitMQConnectionFactory().newConnection();

Channel channel = connection.createChannel();

try {

  Map<String, Object> headers = new HashMap<>();

  headers.put(ACCESS_TOKEN_HEADER, getPreparedUserToken());

  AMQP.BasicProperties properties = (new AMQP.BasicProperties()).builder().replyTo(MessageService.getTempQueueName()).headers(headers).build(); 

  MessageBean message = new MessageBean();

  message.setTemporaryId(mTemporaryId);

  message.setAttachments(attachments);

  message.setType(type.getType());

  Gson gson = new Gson();

  String messageJson = gson.toJson(message);

  channel.basicPublish(OUTGOING_EXCHANGE, routeId, properties, messageJson.getBytes());

 

Thus, RabbitMQ message broker allows to develop effective mobile messengers for iOS and Android alike, completely solving the issue of communication with the application, which allows developers to pay more attention and devote more time to implementing the business logic of the solution.

 

RabbitMq message broker for messenger development. Tips for developers
4.33 (86.67%) 6 votes
×
Яндекс.Метрика

We're moving to our new site. Check out our new slick design! Let's do it!