This project is part of Eventuate, which is a microservices collaboration platform.
This application demonstrates two key patterns:
The application consists of three services:
-
Order Service
- manages orders -
Customer Service
- manages customers -
Order History Service
- maintains the order history
All services are implemented using Spring Boot, JPA and the Eventuate Tram framework, which provides transactional publish/subscribe.
The Order Service
uses a choreography-based saga to enforce the customer’s credit limit when creating orders.
The Order History Service
implements a CQRS view and subscribes to domain events published by the Order Service
and Customer Service
Scroll down to get a tour of a code within a Github Codespace or Visual Studio Code.
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. 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:
-
Look at the Orchestration-based saga example
-
Read the Saga pattern
-
Look at MicroCPH 2019 presentation
-
Read about sagas in my Microservices patterns book
The saga for creating an Order
consists of the follow steps:
-
The Order Service creates an
Order
in aPENDING
state and publishes anOrderCreated
event -
The
Customer Service
receives the event attempts to reserve credit for thatOrder
. It publishes either aCredit Reserved
event or aCreditLimitExceeded
event. -
The
Order Service
receives the event and changes the state of the order to eitherAPPROVED
orREJECTED
.
The CQRS pattern implements queries that retrieves data from multiple services. It maintains a queryable replica of the data by subscribing to domain events published by the services that own the data.
In this example, the Order History Service
maintains a CQRS view in MongoDB by subscribing to domain events published by the Order Service
and Customer Service
.
The CQRS view stores each customer as a MongoDB document that contains information the customer and their orders.
To learn more about why you need CQRS if you are using microservices:
-
Read the CQRS pattern
-
Look at GOTO Chicago 2019 presentation
-
Read about CQRS in my Microservices patterns book
The services uses the Eventuate Tram framework to communicate asynchronously using events. The flow for publishing a domain event using Eventuate Tram is as follows:
-
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 (or Postgres WAL) and publishes messages to Apache Kafka. -
A service subscribes to the events, updates its database, and possibly publishes more events.
The following diagram shows the architecture of the Customers and Orders application.
The application consists of three services: Customer Service
, Order Service
, and Order History Service
The Customer Service
implements a REST API for managing customers.
The service persists the Customer
JPA entity in a MySQL/MsSQL/Postgres database.
Using Eventuate Tram
, it publishes Customer
domain events that are consumed by the Order Service
.
For more information, see the microservice canvas for the Customer Service
.
The Order Service
implements REST API for managing orders.
The service persists the Order
JPA entity in MySQL/MsSQL/Postgres database.
Using Eventuate Tram
, it publishes Order
domain events that are consumed by the Customer Service
.
For more information, see the microservice canvas for the Order Service
.
The Order History Service
implements REST API for querying a customer’s order history
This service subscribes to events published by the Order Service
and Customer Service
and updates a MongoDB-based CQRS view.
For more information, see the microservice canvas for the Order History Service
.
Start the application and the required infrastructure services by running either
./gradlew :end-to-end-tests:runApplicationMySQL
or
./gradlew :end-to-end-tests:runApplicationPostgres
This command starts the containers on unique ports. It prints out the home page URL.
There are a couple of ways to interact with the application: using the Swagger UIs or using curl
.
Once the application has started, visit the home page URL to see the URLs for the Swagger UIs and the API Gateway.
You can also use curl
to interact with the services via the API Gateway
- note you need to replace port 8080 with the correct port for the API Gateway
.
First, let’s create a customer:
$ curl -X POST --header "Content-Type: application/json" -d '{
"creditLimit": {
"amount": 5
},
"name": "Jane Doe"
}' http://localhost:8080/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:8080/orders
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"orderId": 1
}
Next, check the status of the Order
:
$ curl -X GET http://localhost:8080/orders/1
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"orderId": 1,
"orderState": "APPROVED"
}
Finally, look at the customer’s order history in the Order History Service
:
$ curl -X GET --header "Accept: */*" "http://localhost:8080/customers/1/orderhistory"
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"id": 1,
"orders": {
"1": {
"state": "APPROVED",
"orderTotal": {
"amount": 4
}
}
},
"name": "Chris",
"creditLimit": {
"amount": 100
}
}
I’ve configured a Code Tour that will walk through the code in either Visual Studio Code or Github Codespaces.
-
If necessary, install the Code Tour extension from the Visual Studio Code Marketplace.
-
Use the
CodeTour: Start Tour
command from the command palette to start the tour.
- Create a codespace.
- If necessary, install the Code Tour extension from the Visual Studio Code Marketplace.
- Use the
CodeTour: Start Tour
command from the command palette to start the tour.
Don’t hesitate to create an issue or see