Skip to content
Microservices, Sagas, Orchestration, Eventuate Tram, Micronaut
Java Shell TSQL Dockerfile
Branch: master
Clone or download
cer Merge pull request #3 from dartartem/master
Supported swagger ui. Fixed containers startup.
Latest commit 5844474 Oct 5, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci initial version Sep 3, 2019
common initial version Sep 3, 2019
customer-api initial version Sep 3, 2019
customer-backend initial version Sep 3, 2019
customer-service updated swagger ui Oct 4, 2019
customer-web-api initial version Sep 3, 2019
end-to-end-tests initial version Sep 3, 2019
gradle initial version Sep 3, 2019
images Fixed container startup. Added swagger. Oct 3, 2019
integration-tests-common Added in-memory integration tests. Sep 4, 2019
integration-tests-in-memory Added in-memory integration tests. Sep 4, 2019
integration-tests Added in-memory integration tests. Sep 4, 2019
mysql Moved docker image version config to gradle Sep 13, 2019
order-backend
order-service updated swagger ui Oct 4, 2019
order-web-api initial version Sep 3, 2019
postgres Moved docker image version config to gradle Sep 13, 2019
.gitignore initial version Sep 3, 2019
README.adoc Merge branch 'master' of https://github.com/eventuate-tram-examples/e… Oct 3, 2019
_build-and-test-all.sh Moved docker image version config to gradle Sep 13, 2019
build-and-test-all-mysql.sh initial version Sep 3, 2019
build-and-test-all-postgres.sh
build-and-test-everything.sh initial version Sep 3, 2019
build.gradle Fixed container startup. Added swagger. Oct 3, 2019
docker-compose-mysql.yml Moved docker image version config to gradle Sep 13, 2019
docker-compose-postgres.yml Moved docker image version config to gradle Sep 13, 2019
gradle.properties updated eventuate util Oct 4, 2019
gradlew initial version Sep 3, 2019
gradlew.bat initial version Sep 3, 2019
mysql-cli.sh initial version Sep 3, 2019
postgres-cli.sh initial version Sep 3, 2019
set-env-mysql.sh initial version Sep 3, 2019
set-env-postgres.sh initial version Sep 3, 2019
set-env.sh initial version Sep 3, 2019
settings.gradle Added in-memory integration tests. Sep 4, 2019
wait-for-mysql.sh initial version Sep 3, 2019
wait-for-postgres.sh initial version Sep 3, 2019
wait-for-services.sh initial version Sep 3, 2019

README.adoc

Eventuate Tram Sagas Customers and Orders - for Micronaut

This application demonstrates how to maintain data consistency in an Java/JDBC/JPA-based microservice architecture using sagas.

The application consists of two services:

  • Order Service - creates orders

  • Customer Service - manages customers

Both services are implemented using Micronaut, JPA and the Eventuate Tram Saga framework

The Order Service uses a saga to enforce the customer’s credit limit when creating orders.

About sagas

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.

To learn more about why you need sagas if you are using microservices:

There are two main ways to coordinate sagas: orchestration and choreography. Please see Choreograpy version of the Customers and Orders example to learn about choreography-based sagas. This example uses orchestration-based sagas, where a saga (orchestration) object invokes the participants.

A saga orchestrator is a persistent object that does one of two things:

  1. On startup, it sends a command message to a participant

  2. When it receives a reply, it updates its state and sends a command message to the next participant.

The Create Order Saga

The following diagrams shows how the saga for creating an Order works:

Orchestration flow

It consists of the follow steps:

  1. The Order Service creates an Order in a pending state

  2. The Order Service creates a CreateOrderSaga to coordinate the creation of the order.

  3. The CreateOrderSaga sends a ReserveCredit command to the CustomerService

  4. The Customer Service receives the command and attempts to reserve credit for that Order. It replies with a message indicating the outcome.

  5. The CreateOrderSaga receives the reply

  6. It send either an ApproveOrder or a RejectOrder command to the OrderService

  7. The Order Service receives the command and changes state of the order to either approved or rejected.

Architecture

The following diagram shows the architecture of the Customers and Orders application.

Eventuate Tram Customer and Order Orchestration Architecture

The application consists of two services:

  • Customer Service - implements the REST endpoints for managing customers. The service persists the Customer JPA entity in a MySQL/Postgres database. Using the Eventuate Tram Saga framework, it processes command messages, updates its the Customer entity, and sends back a reply message.

  • Order Service - implements a REST endpoint for managing orders. The service persists the Order JPA entity and the CreateOrderSaga in MySQL/Postgres database. Using the Eventuate Tram Saga framework, it sends command messages and processes replies.

The Eventuate Tram CDC service tracks inserts into the MESSAGE table using the MySQL binlog and publishes messages to Apache Kafka.

Building and running

Note: you do not need to install Gradle since it will be downloaded automatically. You just need to have Java 8 installed.

First, build the application

./gradlew assemble

Next, launch the services using Docker Compose:

export DOCKER_HOST_IP=...
./gradlew mysqlComposeBuild
./gradlew mysqlComposeUp

Note:

  1. You can also run the Postgres version using ./gradlew postgresComposeBuild and ./gradlew postgresComposeUp

  2. You need to set DOCKER_HOST_IP before running Docker Compose. This must be an IP address or resolvable hostname. It cannot be localhost. See this guide to setting DOCKER_HOST_IP for more information.

Using the application

Once the application has started, you can use the application via the Swagger UI:

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://${DOCKER_HOST_IP}: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://${DOCKER_HOST_IP}: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://${DOCKER_HOST_IP}:8081/orders/1

HTTP/1.1 200
Content-Type: application/json;charset=UTF-8

{
  "orderId": 1,
  "orderState": "APPROVED"
}

Got questions?

Don’t hesitate to create an issue or see

You can’t perform that action at this time.