Skip to content
Microservices, Sagas, Choreography, Eventuate Tram, Micronaut
Java Shell Dockerfile Groovy
Branch: master
Clone or download
cer Merge pull request #3 from dartartem/master
Swagger ui is moved to eventuate util
Latest commit 7096c71 Oct 4, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Removed publishing of Docker images (for now) Sep 30, 2019
buildSrc/src/main/groovy Supported micronaut for customer service Jul 10, 2019
common Removed dto objects Sep 6, 2019
customer-backend Removed dto objects Sep 6, 2019
customer-service updated swagger ui Oct 4, 2019
customer-web-api Removed dto objects Sep 6, 2019
end-to-end-tests Removed dto objects Sep 6, 2019
gradle Supported micronaut for customer service Jul 10, 2019
images Supported micronaut for customer service Jul 10, 2019
order-backend Removed dto objects Sep 6, 2019
order-history-backend Removed dto objects Sep 6, 2019
order-history-common Removed dto objects Sep 6, 2019
order-history-service updated swagger ui Oct 4, 2019
order-service updated swagger ui Oct 4, 2019
order-web-api Removed dto objects Sep 6, 2019
.gitignore initial commit Jul 9, 2019
LICENSE.md initial commit Jul 9, 2019
README.adoc
_build-and-test-all.sh Moved docker image version config to gradle Sep 13, 2019
_set-env.sh Supported micronaut for customer service Jul 10, 2019
build-and-test-all-mysql-binlog.sh Moved docker image version config to gradle Sep 13, 2019
build-and-test-all-postgres-polling.sh Moved docker image version config to gradle Sep 13, 2019
build-and-test-all-postgres-wal.sh Moved docker image version config to gradle Sep 13, 2019
build-and-test-everything.sh Supported micronaut for customer service Jul 10, 2019
build.gradle Start MySQL before starting services Sep 30, 2019
customer-service-canvas.adoc Supported micronaut for customer service Jul 10, 2019
customer-service-canvas.png Supported micronaut for customer service Jul 10, 2019
docker-compose-mysql-binlog.yml Moved docker image version config to gradle Sep 13, 2019
docker-compose-postgres-polling.yml Moved docker image version config to gradle Sep 13, 2019
docker-compose-postgres-wal.yml Moved docker image version config to gradle Sep 13, 2019
gradle.properties updated eventuate util Oct 4, 2019
gradlew Supported micronaut for customer service Jul 10, 2019
gradlew.bat Supported micronaut for customer service Jul 10, 2019
mongodb-cli.sh Supported micronaut for customer service Jul 10, 2019
mysql-cli.sh Supported micronaut for customer service Jul 10, 2019
order-history-service-canvas.adoc Supported micronaut for customer service Jul 10, 2019
order-history-service-canvas.png
order-service-canvas.adoc Supported micronaut for customer service Jul 10, 2019
order-service-canvas.png Supported micronaut for customer service Jul 10, 2019
postgres-cli.sh Supported micronaut for customer service Jul 10, 2019
set-env-mysql.sh Supported micronaut for customer service Jul 10, 2019
set-env-postgres.sh Supported micronaut for customer service Jul 10, 2019
settings.gradle Supported micronaut for customer service Jul 10, 2019
wait-for-mysql.sh Supported micronaut for customer service Jul 10, 2019
wait-for-postgres.sh Supported micronaut for customer service Jul 10, 2019
wait-for-services.sh Supported micronaut for customer service Jul 10, 2019

README.adoc

Eventuate Tram Customers and Orders - Micronaut version

This application demonstrates two key patterns:

  • Sagas - implement transactions that span services

  • CQRS - implement queries that retrieve data from multiple services.

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 Micronaut, 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

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. To learn more about orchestration, please look at the Orchestration-based saga example 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.

The Create Order saga

The saga for creating an Order consists of the follow steps:

  1. The Order Service creates an Order in a PENDING state and publishes an OrderCreated event

  2. The Customer Service receives the event attempts to reserve credit for that Order. It publishes either a Credit Reserved event or a CreditLimitExceeded event.

  3. The Order Service receives the event and changes the state of the order to either APPROVED or REJECTED.

About Command Query Responsibility Segregation (CQRS)

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:

Transactional messaging with Eventuate Tram

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:

  1. Eventuate Tram inserts events into the MESSAGE table as part of the ACID transaction that updates the JPA entity.

  2. The Eventuate Tram CDC service tracks inserts into the MESSAGE table using the MySQL binlog (or Postgres WAL) and publishes messages to Apache Kafka.

  3. A service subscribes to the events, updates its database, and possibly publishes more events.

Architecture

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

Eventuate Tram Customer and Order Architecture

The application consists of three services: Customer Service, Order Service, and Order History Service

Customer Service

The Customer Service implements a REST API for managing customers. The service persists the Customer JPA entity in a MySQL/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.

customer service canvas

Order Service

The Order Service implements REST API for managing orders. The service persists the Order JPA entity in MySQL/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.

order service canvas

Order History 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.

order history service canvas

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 mysqlbinlogComposeBuild
./gradlew mysqlbinlogComposeUp

Note:

  1. You can also run the Postgres version using ./gradlew postgrespollingComposeUp or ./gradlew postgreswalComposeUp

  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
}

Next, check the status of the Order in the Order Service:

$ 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"
}

Finally, look at the customer’s order history in the Order History Service:

$ curl -X GET --header "Accept: */*" "http://${DOCKER_HOST_IP}:8083/customers/1"

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
  }
}

Got questions?

Don’t hesitate to create an issue or see

You can’t perform that action at this time.