This project is part of Eventuate, which is a microservices collaboration platform.
This application demonstrates how to maintain data consistency in an Java/JDBC/JPA-base microservice architecture using sagas. It’s a choreography-based saga version of Eventuate Tram Sagas Customers and Orders
The application consists of two services:
-
Customer Service- manages customers -
Order Service- creates orders -
Order History Service- a CQRS view service that maintains a customer’s order history
Both services are implemented using Spring Boot, JPA and the Eventuate Tram framework, which provides transactional publish/subscribe over Redis Streams.
The Order Service uses a choreography-based saga to enforce the customer’s credit limit when creating orders.
Sagas are a mechanism for maintaining data consistency in a microservice architecture. A saga is a sequence of transactions, each of which is local to a service.
There are two main ways to coordinate sagas: orchestration and choreography. Please see example to learn about orchestration-based sagas. This example uses choreography-based sagas, which use domain events for coordination. Each step of a saga updates the local database and publishes a domain event. The domain event is processed by an event handler, which performs the next local transaction.
To learn more about why you need sagas if you are using microservices:
-
read the Saga pattern
-
read about sagas in my Microservice patterns book
-
watch my microXchg 2018 presentation
The saga for creating an Order consists of the follow steps:
-
The Order Service creates an
Orderin a pending state and publishes anOrderCreatedevent -
The
Customer Servicereceives the event attempts to reserve credit for thatOrder. It publishes either aCredit Reservedevent or aCreditLimitExceededevent. -
The
Order Servicereceives the event and changes the state of the order to eitherapprovedorrejected.
CQRS is a pattern for implementing queries that retrieve data from multiple services. A service maintains a easily queried replica of the data by subscribing to events published by services that own the data.
The following diagram shows the architecture of the Customers and Orders application.
The application consists of three services:
-
Customer Service- implements the REST endpoints for managing customers. The service persists theCustomerJPA entity in a MySQL/Postgres database. UsingEventuate Tram, it publishesCustomerdomain events that are consumed by theOrder Serviceand theOrder History Service. -
Order Service- implements RESTs endpoint for managing orders. The service persists theOrderJPA entity in MySQL/Postgres database. UsingEventuate Tram, it publishesOrderdomain events that are consumed by theCustomer Serviceand theOrder History Service. -
Order History Service- a CQRS view service that maintains a customer’s order history in Redis. It provides a REST endpoint for retrieving the order history.
There is also:
-
Message Broker- Redis Streams -
Order History Database- Redis
A service publishes events using Eventuate Tram.
Eventuate Tram inserts events into the MESSAGE table as part of the ACID transaction that updates the JPA entity.
The Eventuate Tram CDC service tracks inserts into the MESSAGE table using the MySQL binlog and publishes messages to the message broker, which in this example is Redis (Streams).
A service subscribes to the events and updates its JPA entities in response.
Note: you do not need to install Gradle since it will be downloaded automatically. You just need to have Java 8 installed.
Build and launch the services using Docker Compose invoking with Docker Compose Gradle Plugin:
./gradlew composeUpNote: If the containers aren’t accessible via localhost - e.g. you are using Docker Toolbox - you will first have to set ${DOCKER_HOST_IP} and use it instead of localhost.
See this guide to setting DOCKER_HOST_IP for more information.
Once the application has started, you can use the application via the Swagger UI:
-
Customer Service-http://localhost:8081/swagger-ui.html -
Order Service-http://localhost:8082/swagger-ui.html -
Order History Service-http://localhost:8083/swagger-ui.html
You can also use curl to interact with the services.
First, let’s create a customer:
$ curl -X POST --header "Content-Type: application/json" -d '{
"creditLimit": {
"amount": 5
},
"name": "Jane Doe"
}' http://localhost:8082/customers
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"customerId": 1
}Next, create an order:
$ curl -X POST --header "Content-Type: application/json" -d '{
"customerId": 1,
"orderTotal": {
"amount": 4
}
}' http://localhost:8081/orders
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"orderId": 1
}Finally, check the status of the Order:
$ curl -X GET http://localhost:8081/orders/1
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"orderId": 1,
"orderState": "APPROVED"
}Don’t hesitate to create an issue or see

