Eventual Consistency with Integration Events using RabbitMq

Ebubekir Dinc
4 min readDec 9, 2023

--

This article is part of my Microservices and Cloud-Native Applications series. You can find the other parts of the series below.

  1. Saga Orchestration using MassTransit in .NET
  2. API Gateway with Ocelot
  3. Authorization and Authentications with IdentityServer
  4. Eventual Consistency with Integration Events using RabbitMq
  5. Distributed Logging with ElasticSearch, Kibana, and SeriLog
  6. Resiliency and Fault Tolerance with Polly
  7. Health Check with WatchDogs in a Microservices Architecture
  8. Distributed Tracing with Jaeger and OpenTelemetry in a Microservices Architecture
  9. Metrics to Monitor Microservices with OpenTelemetry and Prometheus

If you want to take a look at the GitHub code, you can access it here: https://github.com/ebubekirdinc/SuuCat

A common consistency paradigm in distributed systems, including microservices architecture, is eventual consistency. Changes made to a system are not instantly propagated to all of the nodes in the system
according to this model. Instead, the modifications are eventually propagated, which means that eventually, all nodes will show the modifications.

In a microservices architecture, each microservice manages its own data store, which can lead to inconsistencies between different microservices’ views of the same data. To address this issue, microservices often use
eventual consistency to ensure that all microservices eventually reflect the same data.

In real-world applications, eventual consistency is achieved using methods like message passing, and versioning. For instance, a microservice might broadcast a message to all other microservices informing them of an update to its data store. Then, each microservice can modify its own data repository to incorporate the modification.

All microservices may not immediately receive the notification and update their data stores. Inconsistencies might exist during this period, but they will eventually get resolved as all microservices update their data stores. This is the result of these microservices being loosely coupled to each other and communicating asynchronously.

SuuCat Microservices Architecture Overview with Ocelot
SuuCat Microservices Architecture Overview

In SuuCat, Eventual Consistency has been implemented using RabbitMq and MassTransit. When a microservice needs to update its data store, it publishes an event to a message broker. Then, other microservices can subscribe to the event and update their data stores accordingly. Think of it as a topic message sent by Azure Service Bus, but here RabbitMq is used. In the real world, you will most likely be using Azure Service Bus or SQS-EventBridge in AWS. In the future, I plan to do a version of this with Azure Service Bus.

RabbitMq can be installed using the following Docker files. More information about the installation is here: https://github.com/ebubekirdinc/SuuCat/wiki/GettingStarted

docker-compose.yml

https://github.com/ebubekirdinc/SuuCat/blob/master/docker-compose.yml
https://github.com/ebubekirdinc/SuuCat/blob/master/docker-compose.yml

docker-compose.override.yml

https://github.com/ebubekirdinc/SuuCat/blob/master/docker-compose.override.yml
https://github.com/ebubekirdinc/SuuCat/blob/master/docker-compose.override.yml

Now that we have the project working, let’s see how we use Eventual Consistency in SuuCat. As you can see in the following code, the SignUp method is an HTTP POST method that creates a new user in the Identity Microservice. When a new user is created, an event named UserCreatedEvent is published using the message broker: RabbitMQ. The UserCreatedEvent contains information about the newly created user, including the user ID, email, and username.

https://github.com/ebubekirdinc/SuuCat/blob/master/src/Services/Identity/Controllers/AuthController.cs
https://github.com/ebubekirdinc/SuuCat/blob/master/src/Services/Identity/Controllers/AuthController.cs

The UserCreatedEventConsumer class in Account Microservice is a consumer that listens for UserCreatedEvent messages and updates the local database in response. The Consume() method of this consumer checks if the user already exists in the local database. If the user doesn’t exist, the consumer creates a new user entity in the local database using the information contained in the UserCreatedEvent. The new user is then saved to the database.

https://github.com/ebubekirdinc/SuuCat/blob/master/src/Services/Account/src/Infrastructure/Consumers/UserCreatedEventComsumer.cs

This implementation of Eventual Consistency ensures that all microservices eventually have consistent user data. The SignUp method creates a new user in one microservice and publishes an event to notify other microservices of the new user.

The UserCreatedEventConsumer listens for this event and updates the local database accordingly. However, it may take some time for the event to propagate to all microservices and for the database to be updated.
As mentioned earlier, during this time, inconsistencies may exist, but they will eventually be resolved as all microservices eventually update their local databases.

More info can be found in SuuCat GitHub.

Imbattable, by Pascal Jousselin http://pjousselin.free.fr Originally posted: https://medium.com/@hugo.oliveira.rocha/handling-eventual-consistency-11324324aec4

--

--