Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Eventuate Local #24

Open
wants to merge 83 commits into
base: wip-customer
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
192db2b
Transfers history - 3rd party transfers
dartandrevinsky Sep 7, 2016
732581a
Merge remote-tracking branch 'remotes/dartandrevinsky/wip-customer' i…
dartpopikyardo Sep 7, 2016
8b5b54e
removed transferStates from AccountInfo
dartpopikyardo Sep 7, 2016
8869563
Transfers history - 3rd party transfers & links to accounts
dartandrevinsky Sep 7, 2016
7c47d59
private-event-sourcing-examples-26
dartpopikyardo Sep 7, 2016
4f1bb4a
Merge remote-tracking branch 'remotes/dartandrevinsky/wip-customer' i…
dartpopikyardo Sep 7, 2016
f9d8180
Merge remote-tracking branch 'remotes/origin/wip-customer' into priva…
dartpopikyardo Sep 7, 2016
c916bc8
fixed getDate()
dartpopikyardo Sep 7, 2016
fd63640
- added password to CustomerInfo
dartpopikyardo Sep 8, 2016
859a01a
- fixed tests
dartpopikyardo Sep 9, 2016
12cc48b
Merge commit '859a01a4bc2372a11a5377d1206235ca12da4417' into wip-cust…
dartandrevinsky Sep 9, 2016
258646a
Password on login & registration
dartandrevinsky Sep 9, 2016
df4204f
- shouldCreateAccountsAndTransferMoney fix
dartpopikyardo Sep 9, 2016
0b39ba6
Error reporting for Sign In & Sign Up
dartandrevinsky Sep 12, 2016
20cc17c
Form validation for Sign In & Sign Up
dartandrevinsky Sep 13, 2016
91f6fde
should fix issue #23
dartpopikyardo Sep 13, 2016
72a4ab1
should fix issue #38
dartpopikyardo Sep 14, 2016
8f4ac83
added timestamp to make AccountDeletedEvent not empty
dartpopikyardo Sep 15, 2016
c52b803
Merge branch 'wip-customer' into private-event-sourcing-examples-38
dartandrevinsky Sep 15, 2016
e551b3d
Account & bookmarks deletion
dartandrevinsky Sep 15, 2016
6c2700b
Merge remote-tracking branch 'remotes/dartandrevinsky/private-event-s…
dartpopikyardo Sep 15, 2016
5f11423
Account & bookmarks deletion - bug fixed
dartandrevinsky Sep 15, 2016
f4ec434
fixed tests
dartpopikyardo Sep 15, 2016
fe220a8
Merge remote-tracking branch 'remotes/dartandrevinsky/private-event-s…
dartpopikyardo Sep 15, 2016
61a1153
uncomment test methods
dartpopikyardo Sep 15, 2016
b0bfa7f
fixed api gateway properties
dartpopikyardo Sep 15, 2016
fe20a3f
added dummmy fields to AccountDeletedEvent
dartpopikyardo Sep 16, 2016
459e291
Code overhaul & cleanup
dartandrevinsky Sep 16, 2016
93fc13e
fixed GatewayController
dartpopikyardo Sep 16, 2016
5c96941
Issue #42, endpoints fixed
dartandrevinsky Sep 16, 2016
8312cb3
Merge remote-tracking branch 'remotes/dartandrevinsky/private-event-s…
dartpopikyardo Sep 16, 2016
fe925ac
fix issue #31
dartpopikyardo Sep 16, 2016
c88ba88
Improved Eventuate Local support
cer Sep 17, 2016
5fd5b71
Delete 3rd P/Account - endpoints
dartandrevinsky Sep 19, 2016
0f21a05
- splitted account deletion to 2 separate endpoints: /api/customers/{…
dartpopikyardo Sep 20, 2016
473743d
merged with upstream/wip-customer
dartpopikyardo Sep 20, 2016
a947cbf
merged with upstream/wip-customer
dartpopikyardo Sep 20, 2016
b06d607
fixed typo in api-gateway properties
dartpopikyardo Sep 20, 2016
974f2b9
updated AbstractRestAPITest
dartpopikyardo Sep 20, 2016
50fdad2
Merge remote-tracking branch 'remotes/dartandrevinsky/private-event-s…
dartpopikyardo Sep 20, 2016
f4b35d0
added JAVA_OPTS
dartpopikyardo Sep 20, 2016
d5d6fb9
Eternal loading for deleted accounts - fixed
dartandrevinsky Sep 20, 2016
ab4026a
removed redundant EventHandler method from accounts-commandside-backend
dartpopikyardo Sep 20, 2016
334df47
private-event-sourcing-examples-46 Write a single, simple protractor …
dartandrevinsky Sep 20, 2016
2c97630
Merge pull request #39 from dartpopikyardo/private-event-sourcing-exa…
cer Sep 22, 2016
2db8e09
[WIP] signupPage e2e test scenario
dartandrevinsky Sep 22, 2016
00f5b5a
Merge commit '2c97630aa6100ac8b507b71c4a3468540996f136' into wip-cust…
dartandrevinsky Sep 22, 2016
0c573e9
Merge branch 'wip-customer' into private-event-sourcing-examples-38
dartandrevinsky Sep 22, 2016
abeb29b
Merge branch 'private-event-sourcing-examples-38' into private-event-…
dartandrevinsky Sep 22, 2016
727c771
Merge pull request #49 from dartandrevinsky/private-event-sourcing-ex…
cer Sep 23, 2016
e4a0d67
- fix issue #48
dartpopikyardo Sep 23, 2016
e01e98a
Merge remote-tracking branch 'remotes/upstream/wip-customer' into pri…
dartpopikyardo Sep 23, 2016
b2d1356
Simplified dependencies
cer Sep 23, 2016
93a51f5
private-event-sourcing-examples-46 Write a single, simple protractor …
dartandrevinsky Sep 20, 2016
e94e24d
[WIP] signupPage e2e test scenario
dartandrevinsky Sep 22, 2016
85e6c57
Merge branch 'private-event-sourcing-examples-46' of https://github.c…
dartandrevinsky Sep 23, 2016
f740098
Merge commit 'e01e98a50875f85f98a80376f1580b1c901bef38' into private-…
dartandrevinsky Sep 26, 2016
790c76c
private-event-sourcing-examples-57 update EventuateDependencyPlugin.g…
dartpopikyardo Sep 26, 2016
29cfdb0
private-event-sourcing-examples-46 Write a single, simple protractor …
dartandrevinsky Sep 26, 2016
04fe904
Merge remote-tracking branch 'remotes/upstream/wip-customer' into pri…
dartpopikyardo Sep 27, 2016
4b78658
fixed issue #54
dartpopikyardo Sep 27, 2016
7260376
Merge remote-tracking branch 'remotes/dartandrevinsky/private-event-s…
dartpopikyardo Sep 27, 2016
4b74d2c
fixed a non-404 responce in the case when the customer is not found
dartpopikyardo Sep 27, 2016
68a1269
fix AuthControllerIntegrationTest
dartpopikyardo Sep 27, 2016
ebca25a
Merge commit '68a126908895da2e62ddc8955e1c8790195a6e9b' into private-…
dartandrevinsky Sep 27, 2016
01bc170
private-event-sourcing-examples-46 Write a single, simple protractor …
dartandrevinsky Sep 28, 2016
823d571
private-event-sourcing-examples-46 Write a single, simple protractor …
dartandrevinsky Sep 28, 2016
c2e4df4
Merge pull request #53 from dartpopikyardo/private-event-sourcing-exa…
cer Sep 28, 2016
bb9e40e
Merge pull request #58 from dartpopikyardo/private-event-sourcing-exa…
cer Sep 28, 2016
8b71464
Merge pull request #56 from dartandrevinsky/private-event-sourcing-ex…
crcinc Sep 30, 2016
4185064
Simplified README.md
cer Sep 30, 2016
e75b00b
Fixed README.md
cer Oct 2, 2016
60a1986
Improved wording
cer Oct 2, 2016
e143d0f
- improved build-and-test-all-eventuate-local.sh and _build-and-test-…
dartpopikyardo Oct 3, 2016
db05a80
fixed logback files
dartpopikyardo Oct 7, 2016
1c0ae8a
converted all docker-compose files to use build: rather than volumes …
dartpopikyardo Oct 10, 2016
106ee9e
fixed docker-compose script
dartpopikyardo Oct 10, 2016
c8b0185
fixed docker-compose script
dartpopikyardo Oct 10, 2016
f4a7dbe
fixed docker-compose script
dartpopikyardo Oct 10, 2016
623554b
- simplified Dockerfiles
dartpopikyardo Oct 11, 2016
903a4b0
- added docker-compose build
dartpopikyardo Oct 11, 2016
5bd3f36
fixed build-and-test-all script
dartpopikyardo Oct 13, 2016
909ad5f
Merge remote-tracking branch 'remotes/upstream/master' into wip-customer
dartpopikyardo Oct 19, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 50 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Event-Sourcing+CQRS example application
# Event-Sourcing+CQRS example application

This example application is the money transfer application described in my talk [Building and deploying microservices with event sourcing, CQRS and Docker](http://plainoldobjects.com/presentations/building-and-deploying-microservices-with-event-sourcing-cqrs-and-docker/).
This talk describes a way of architecting highly scalable and available applications that is based on microservices, polyglot persistence,
Expand Down Expand Up @@ -35,111 +35,99 @@ The following diagram shows the architecture:

![Money transfer architecture](https://github.com/cer/event-sourcing-examples/wiki/i/applicationarchitecture.png)

There are four logical services:
There are the following logical services:

* Customers (command-side) - REST API for creating customers
* Accounts (command-side) - REST API for creating accounts
* Money transfers (command-side) - REST API for transferring money
* Account view updater (query-side) - subscribes to events and updates a MongoDB View
* Account view reader (query-side) - REST API for retrieving accounts
* Customers (query-side) - subscribes to events and updates a MongoDB View, and provides an API for retrieving customers
* Accounts (query-side) - subscribes to events and updates a MongoDB View, and provides an API for retrieving accounts

There is also an [API gateway](http://microservices.io/patterns/apigateway.html) service that acts as a Facade in front of the services.

One of the neat things about the modular architecture is that there are two ways to deploy these four services:

* monolithic-service - all services are packaged as a single Spring Boot executable JAR
* Microservices - three separate Spring Boot executable JARs
* customer-command-side-service - command-side customers
* accounts-command-side-service - command-side accounts
* transactions-command-side-service - command-side money transfers
* accounts-query-side-service - Account View Updater and Account View Reader
* customers-query-side-service - query-side customers
* accounts-query-side-service - query-side accounts
* api-gateway-service - API gateway service

# About the examples

There are currently the following versions of the example application:

* java-spring - a Java and Spring Boot example
* scala-spring - a Scala and Spring Boot example
* scala-spring - a Scala and Spring Boot example (NOTE: this version is lagging the Java Spring and hasn't been updated in a longtime.)

Other examples will be added shortly including a Scala/Play example.

For more information, please see the [wiki](../../wiki)

# About the Event Store
# About the Eventuate Platform

The application uses one of two event stores:
The application is built using [Eventuate](http://eventuate.io/), which is an application platform for writing transactional microservices.
It provides a simple yet powerful event-driven programming model that is based on event sourcing and Command Query Responsibility Segregation (CQRS).
Eventuate solves the distributed data management problems inherent in a microservice architecture.
It consists of a scalable, distributed event store and client libraries for various languages and frameworks including Java, Scala, and the Spring framework.

* Embedded SQL-based event store, which is great for integration tests.
It is also used when running the monolithic version of the application.
* Event Store server - this is a full featured event store.
See this [wiki page](../../wiki/AboutTheEventStoreServer) for more details.
There are two versions of Eventuate:

# Building the application (and running the tests)
* [Eventuate SaaS server](http://eventuate.io/usingeventuate.html) - this is a full featured event store that is hosted on AWS
* [Eventuate Local](http://eventuate.io/usingeventuate.html) - an open-source event store that is built using MySQL and Kafka

Both versions of the application use Gradle.
To build an application, execute this command in the application's top-level directory:
There is also an embedded test event store, which is great for integration tests.

```
./gradlew assemble
```
# Building and running the microservices

Note: you do not need to install Gradle.
It will be automatically downloaded by `./gradlew`.
This is a Gradle project.
However, you do not need to install Gradle since it will be downloaded automatically.
You just need to have Java 8 installed.

This will build a Spring Boot jar in each of the `*-service` directories.
The details of how to build and run the services depend slightly on whether you are using Eventuate SaaS or Eventuate Local.

You can also run the tests using `gradle build`.
However, you must set some environment variables.
## Building and running using Eventuate SaaS

First, you need to tell the query side code how to connect to MongoDB:
First, must [sign up to get your credentials](https://signup.eventuate.io/) in order to get free access to the SaaS version.

```
export SPRING_DATA_MONGODB_URI=mongodb://192.168.59.103/yourdb
```
Next, build the application

[Docker Compose](https://docs.docker.com/compose/) is a great way to run MongoDB.
You can run the `docker-compose up -d mongodb` to run MongoDB and then set `SPRING_DATA_MONGODB_URI` as follows:
```
export SPRING_DATA_MONGODB_URI=mongodb://$(docker-machine ip default)/yourdb
cd java-spring
./gradlew assemble -P eventuateLocal=true
```

Second, some of the tests in accounts-command-side-service, transactions-command-side-service, accounts-query-side-service and e2e-test require you to set some environment variables that tell them how to connect to the Event Store server.
But don't worry.
The build is configured to ignore failures for those projects.

# Running the application

To run the application, you must to set the SPRING_DATA_MONGODB_URI environment variable, which tells the query services how to connect to MongoDB.

There are a couple of different ways of running the application.

## Running the monolithic application

One option is to run the self-contained monolithic application.
It uses the embedded event store.

Simply use this command:
Next, you can launch the services using [Docker Compose](https://docs.docker.com/compose/):

```
java -jar monolithic-service/build/libs/monolithic-service.jar
docker-compose up -d
```

This will start the service running on port 8080 (you can change using the --server.port=9999 option).
Finally, you can open the home page, which is served up by the API Gateway: `http://$DOCKER_HOST_IP:8080`

Once the service has started you can open the Swagger UI: http://localhost:8080/swagger-ui.html.
You can then:
Note: `DOCKER_HOST_IP` is the IP address of the machine where Docker is running, e.g. the IP address of the VirtualBox VM.

1. Create two accounts (save the account ids)
2. Create a money transfer
3. View the updated account balances
## Building and running using Eventuate Local

## Running the microservices
First, build the application

The other option is to run the services separately.
However, in order to do this you need to [get credentials for the Event Store](../../wiki/AboutTheEventStoreServer).
```
cd java-spring
./gradlew assemble -P eventuateDriver=local
```

One way to run the services is to use the scripts `run-all-services.sh`, which runs the services, and `kill-all-services.sh`, which kills the processes.
Next, launch the services using [Docker Compose](https://docs.docker.com/compose/):

A much better way, however, is to use Docker Compose.
Simply run the command `docker-compose up` to launch the services.
This will create containers for MongoDB and each of the services.
```
export DOCKER_HOST_IP=...
docker-compose -f docker-compose-eventuate-local.yml up -d
```

You can now, for example, use the curl commands in `handy-curl-commands.sh` to interact with the server.
Note: You need to set `DOCKER_HOST_IP` before running Docker Compose.
This must be an IP address or resolvable hostname.
It cannot be `localhost`.

You can also use the Swagger UI exposed by each service `http://host:port/swagger-ui.html`.
Finally, you can open the home page, which is served up by the API Gateway: `http://$DOCKER_HOST_IP:8080`
103 changes: 0 additions & 103 deletions Vagrantfile

This file was deleted.

24 changes: 14 additions & 10 deletions _build-and-test-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

set -e

if [ -z "$DOCKER_HOST_IP" ] ; then
if [ -z "$DOCKER_HOST" ] ; then
export DOCKER_HOST_IP=`hostname`
else
echo using ${DOCKER_HOST?}
XX=${DOCKER_HOST%\:*}
export DOCKER_HOST_IP=${XX#tcp\:\/\/}
fi
echo set DOCKER_HOST_IP $DOCKER_HOST_IP
fi

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

DOCKER_COMPOSE="docker-compose -p event-sourcing-examples"
Expand All @@ -26,16 +37,8 @@ if [ "$1" = "--no-rm" ] ; then
shift
fi

${DOCKER_COMPOSE?} up -d mongodb
${DOCKER_COMPOSE?} up -d mongodb $EXTRA_INFRASTRUCTURE_SERVICES

if [ -z "$DOCKER_HOST_IP" ] ; then
if which docker-machine >/dev/null; then
export DOCKER_HOST_IP=$(docker-machine ip default)
else
export DOCKER_HOST_IP=localhost
fi
echo set DOCKER_HOST_IP $DOCKER_HOST_IP
fi

if [ -z "$SPRING_DATA_MONGODB_URI" ] ; then
export SPRING_DATA_MONGODB_URI=mongodb://${DOCKER_HOST_IP?}/mydb
Expand All @@ -46,11 +49,12 @@ export SERVICE_HOST=$DOCKER_HOST_IP

./gradlew $* build -x :e2e-test:test

if [ -z "$EVENTUATE_API_KEY_ID" -o -z "$EVENTUATE_API_KEY_SECRET" ] ; then
if [ -z "$EVENTUATE_LOCAL" ] && [ -z "$EVENTUATE_API_KEY_ID" -o -z "$EVENTUATE_API_KEY_SECRET" ] ; then
echo You must set EVENTUATE_API_KEY_ID and EVENTUATE_API_KEY_SECRET
exit -1
fi

${DOCKER_COMPOSE?} build

${DOCKER_COMPOSE?} up -d

Expand Down
6 changes: 0 additions & 6 deletions gradle-all.sh

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,51 @@
import io.eventuate.Event;
import io.eventuate.EventUtil;
import io.eventuate.ReflectiveMutableCommandProcessingAggregate;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountCreditedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitFailedDueToInsufficientFundsEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountDebitedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.AccountOpenedEvent;
import net.chrisrichardson.eventstore.javaexamples.banking.backend.common.accounts.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Account extends ReflectiveMutableCommandProcessingAggregate<Account, AccountCommand> {

private BigDecimal balance;
private boolean deleted;

public List<Event> process(OpenAccountCommand cmd) {
return EventUtil.events(new AccountOpenedEvent(cmd.getCustomerId(), cmd.getTitle(), cmd.getInitialBalance(), cmd.getDescription()));
}

public List<Event> process(DeleteAccountCommand cmd) {
return EventUtil.events(new AccountDeletedEvent());
}

public List<Event> process(DebitAccountCommand cmd) {
if(deleted)
return new ArrayList<>();

if (balance.compareTo(cmd.getAmount()) < 0)
return EventUtil.events(new AccountDebitFailedDueToInsufficientFundsEvent(cmd.getTransactionId()));
else
return EventUtil.events(new AccountDebitedEvent(cmd.getAmount(), cmd.getTransactionId()));
}

public List<Event> process(CreditAccountCommand cmd) {
if(deleted)
return new ArrayList<>();

return EventUtil.events(new AccountCreditedEvent(cmd.getAmount(), cmd.getTransactionId()));
}

public void apply(AccountOpenedEvent event) {
balance = event.getInitialBalance();
}

public void apply(AccountDeletedEvent event) {
deleted = true;
}

public void apply(AccountDebitedEvent event) {
balance = balance.subtract(event.getAmount());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ public CompletableFuture<EntityWithIdAndVersion<Account>> openAccount(String cus
return accountRepository.save(new OpenAccountCommand(customerId, title, initialBalance, description));
}

public CompletableFuture<EntityWithIdAndVersion<Account>> deleteAccount(String accountId) {
return accountRepository.update(accountId, new DeleteAccountCommand());
}
}
Loading