RabbitMQ and SpringBoot for Real-Time Messaging

How to implement a simple real-time and scheduled messaging application using RabbitMQ and SpringBoot framework

Tanbir Ahmed
CodeX
8 min readAug 1, 2021

--

I’ve been watching The Expanse for the last few months. It has space battles, warships, aliens, and lots of other cool sci-fi troops. It also shows some advanced software that allows the space stations to monitor and communicate with all of their space ships and rockets. Got me thinking — do we have the tools to build a backend for something like that today. The first thing that came to my mind —with RabbitMQ and SpringBoot.

The Problem Scenario

We want to build a messaging system for the space station Tyco which monitors different parameters of its space ships and sends personal and common messages(and/or commands) to the spaceships. The ships will send a periodic update to the station. They (the ships) can also have one-to-one communication with the station.

Use Cases

Based on the problem scenario we have three major use cases we need to implement. We are focusing on messaging, not the events triggered by the messages (Hopefully I’ll talk about that in another project)

  1. The spaceships will send periodic updates to the station.
  2. Each ship and the docking station will have real-time one-to-one messaging (“Instant Messaging” in terms of social networks).
  3. The docking station will broadcast a common message to all the ships.

These use cases could be developed utilizing different exchanges available in RabbitMQ. Each ship and the docking station will act both as consumer and producer because of the two-way communication requirement. Follow up here for more details on the exchanges, queues, and routing key if you want details on these concepts. In short,

Exchanges send messages to a specific Queue based on the Routing-key attached to the messages. These exchanges differ in their functionality on how they use the routing key to deliver messages to the queues.

The codes are available on my GitHub. Here I’m showing codes only necessary for explaining the underlying concepts. Before starting here are the properties files for the Station and the Ships.

Send periodic updates to the docking station

We will use the Direct Exchange for sending periodic updates from the spaceships to the station.

Direct Exchange delivers messages to the queues based on the exact match of the attached routing-key.

Each ship can use a common routing key to send updates. @EnableScheduling & @Scheduled annotation could be used to schedule a periodic task. For simplicity, we just send the parameters along with the ship’s name punctuated by a colon (:). The class ParameterFactory creates dummy parameters with random double values. Here is an example:

Using a single routing key to send periodic updates the station

The implementation for sending messages using RabbitMQ API is fairly simple. However, to receive a message the Station needs to configure the direct exchange and bind the queue to the direct exchange with a routing key. It also needs a callback method to handle the message when it arrives at the queue. Here are the codes:

The received message will look like the following in the station's console.

One-to-one communication between ships and the station

Station →Ship: We can again use direct exchange for sending individual messages to the ships using different routing keys. Each of the ships will have its own queue and routing key. We can have any messaging pattern to determine for which ship any message is meant and attach a routing key with the message. I used a messaging pattern like the following.

Using different routing keys to send individual messages to the ships

Here is the code of the Station’s application for sending individual messages to the ships. Using a CLI we can take the input in the correct format and using the MessageHandler class send the message to the intended ship. The code is very straightforward.

To receive the messages the ships need to define it’s own direct exchange, queue, and bind it with a unique routing key. The codes for the ships are almost similar to the station for receiving messages from direct exchange. Hence, only the skeleton is shown here.

Ship →Station: Each ship already has a channel of communication with the station for their regular update. We can take a shortcut here and use the same routing key for sending individual messages to the station.

Broadcast a message to the spaceships

For sending a common message to all the ships at a time from the station, we can use a Fanout Exchange. Fanout exchange delivers messages to all the queues that are bound to it ignoring the routing key. The ships can bind the already existing queue they used for One-to-One messaging to a specific fanout exchange whit out any routing key and the station can just throw a message to the exchange without worrying about the routing key. In my application, I used the following messaging pattern to signal the station to broadcast the message.

Fanout Exchange delivers messages to all the queues that are bound to it ignoring the routing key.

For broadcasting just needed to add a new case like the following in the MessageHandler class of the ship’s application:

The code for receiving the broadcasted message for each ship needs to add the following configurations.

Summary

In this application, each of the ships and the station works both as a consumer and producer. Hence, all of them needed their own queue for keeping the messages. The station needed only one direct exchange and one queue for receiving real-time and scheduled messages. On the other hand, the ships needed two exchanges as there were two types of messages they could receive — individual and common. However, they could use only one queue to bind it to the direct and fanout exchange. The implementation is available here:

--

--

Tanbir Ahmed
CodeX

Java Backend Developer | Data Privacy Researcher