Skip to content

Commit 4098a02

Browse files
committed
Initial version of code
1 parent edd30ea commit 4098a02

File tree

270 files changed

+9222
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

270 files changed

+9222
-0
lines changed

LICENSE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2016 Eventuate, Inc. All rights reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

README.adoc

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
= FTGO example application
2+
3+
This is the example code for my book https://www.manning.com/books/microservice-patterns[Microservice patterns].
4+
5+
== Please note
6+
7+
* The code is still work in progress
8+
* It primarily illustrates the technical aspects of the microservice architecture and so the business logic is minimal
9+
* The documentation is sparse/non-existent and you will need to look in the book
10+
* The application consists of many services and so requires a lot of memory. It runs well, for example, on a 16MB Macbook pro.
11+
* The application's services and the infrastructure services, such as MySQL and Apache Kafka, are deployed using Docker containers.
12+
13+
== Got questions
14+
15+
Please post a message to the https://forums.manning.com/forums/microservice-patterns[book's discussion forum] or create a github issue.
16+
I'll do my best to help you.
17+
18+
== Application architecture
19+
20+
Not surprisingly, this application has a microservice architecture.
21+
There are the following services:
22+
23+
* link:./ftgo-consumer-service[ftgo-consumer-service] - the `Consumer Service`
24+
* link:./ftgo-restaurant-service[ftgo-restaurant-service] - the `Restaurant Service`
25+
* link:./ftgo-order-service[ftgo-order-service] - the `Order Service`
26+
* link:./ftgo-restaurant-order-service[ftgo-restaurant-order-service] - the `Restaurant Order Service`
27+
* link:./ftgo-accounting-service[ftgo-accounting-service] - the `Accounting Service`
28+
* link:./ftgo-order-history-service[ftgo-order-history-service] - a `Order History Service`, which is a CQRS view
29+
* link:./ftgo-api-gateway[ftgo-api-gateway] - the API gateway
30+
31+
== Service design
32+
33+
Key points:
34+
35+
* A service consists of a single Gradle module.
36+
For example, `ftgo-order-service` implements the `Order Service`
37+
* A service is a Spring Boot application
38+
* A service has a Swagger UI `http://.../swagger-ui.html`. See `open-swagger-uis.sh`
39+
* A service typically consists of the following packages:
40+
** domain - domain logic including aggregates
41+
** messaging - messaging adapters
42+
** web - Spring MVC controllers (HTTP adapters)
43+
** main - the main application
44+
* The services use the following other frameworks
45+
** `Eventuate Tram` framework - implements transactional messaging
46+
** `Eventuate Tram Saga` framework - implements sagas
47+
** `Eventuate Client framework` - implements event sourcing
48+
49+
== Chapter by chapter
50+
51+
This section maps the chapters to the code.
52+
53+
=== Chapter 3 Inter-process communication in a microservice architecture
54+
55+
* The services have a REST API
56+
* The services also communicate using the Apache Kafka message broker via the `Eventuate Tram` framework
57+
58+
=== Chapter 4 Managing transactions with sagas
59+
60+
The link:./ftgo-order-service[ftgo-order-service] uses sagas to maintain data consistency:
61+
62+
* link:./ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSaga.java[CreateOrderSaga]
63+
* link:./ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/cancelorder/CancelOrderSaga.java[CancelOrderSaga]
64+
* link:./ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/reviseorder/ReviseOrderSaga.java[ReviseOrderSaga]
65+
66+
The services that participate in these sagas define the following command handlers:
67+
68+
* `Accounting Service` link:./ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandler.java[AccountingServiceCommandHandler]
69+
* `Consumer Service` link:./ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerServiceCommandHandlers.java[ConsumerServiceCommandHandlers]
70+
* `Restaurant Order Service` link:./ftgo-restaurant-order-service/src/main/java/net/chrisrichardson/ftgo/restaurantorderservice/messagehandlers/RestaurantOrderServiceCommandHandler.java[RestaurantOrderServiceCommandHandler]
71+
* `Order Service` link:./ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/service/OrderCommandHandlers.java[OrderCommandHandlers]
72+
73+
74+
75+
=== Chapter 5 Designing business logic in a microservice architecture
76+
77+
All the services' business logic is implemented using Domain-Driven design aggregates.
78+
79+
* `Accounting Service`
80+
** link:./ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/Account.java[`Account`] aggregate in the link:./ftgo-accounting-service[ftgo-accounting-service]
81+
* `Consumer Service`
82+
** link:./ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/Consumer.java[Consumer]
83+
* `Order Service`
84+
** link:./ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/Order.java[Order]
85+
** link:./ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/Restaurant.java[Restaurant]
86+
* `Restaurant Order Service`
87+
** link:./ftgo-restaurant-order-service/src/main/java/net/chrisrichardson/ftgo/restaurantorderservice/domain/Restaurant.java[Restaurant]
88+
** link:./ftgo-restaurant-order-service/src/main/java/net/chrisrichardson/ftgo/restaurantorderservice/domain/RestaurantOrder.java[RestaurantOrder]
89+
* `Restaurant Service`
90+
** link:./ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java[Restaurant]
91+
92+
93+
=== Chapter 6 Developing business logic with event sourcing
94+
95+
* The link:./ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/Account.java[`Account`] aggregate in the link:./ftgo-accounting-service[ftgo-accounting-service] is implemented using event sourcing
96+
97+
=== Chapter 7 Implementing queries in a microservice architecture
98+
99+
* link:./ftgo-order-history-service[ftgo-order-history-service] is an example of a CQRS view
100+
* link:./ftgo-api-gateway[ftgo-api-gateway] uses API composition to implement the REST endpoint for retrieving the order history
101+
102+
=== Chapter 8 External API patterns
103+
104+
* link:./ftgo-api-gateway[ftgo-api-gateway] is the API gateway
105+
106+
107+
== Building and running the application
108+
109+
=== Pre-requisites
110+
111+
* Java 8
112+
* Docker and Docker Compose
113+
* Internet access so that Gradle and Docker can download dependencies and container images
114+
* The link:./ftgo-order-history-service[ftgo-order-history-service] uses AWS DynamoDB and so requires an access key and secret.
115+
116+
=== Building
117+
118+
Build the services using this command:
119+
120+
```
121+
./gradlew assemble
122+
```
123+
124+
=== Setting environment variables
125+
126+
To run the application you must set the `DOCKER_HOST_IP` environment variable to the IP address of where the Docker containers are running:
127+
128+
* Docker toolbox/Virtual machine - IP address of the virtual machine
129+
* Docker for Windows/Mac/Linux - IP address of your laptop/desktop
130+
131+
Please do NOT set it to the (unresolvable) hostname of your machine, `localhost` or `127.0.0.1`.
132+
133+
You must also set the AWS environment variables.
134+
135+
=== Running the application
136+
137+
Run the application using this command:
138+
139+
```
140+
docker-compose up -d
141+
```
142+
143+
This can take a while
144+
145+
=== Using the application
146+
147+
Use the services Swagger UIs to invoke the services.
148+
149+
* Create consumer - `http://${DOCKER_HOST_IP?}:8081/swagger-ui.html`
150+
* Create a restaurant - `http://${DOCKER_HOST_IP?}:8084/swagger-ui.html`
151+
* Create an order - `http://${DOCKER_HOST_IP?}:8082/swagger-ui.html`
152+
* View the order - `http://${DOCKER_HOST_IP?}:8082/swagger-ui.html`
153+
* View the order history - `http://${DOCKER_HOST_IP?}:8086/swagger-ui.html`
154+
155+
You can also access the application via the `API Gateway` at `http://${DOCKER_HOST_IP?}:8087`.
156+
However, currently it doesn't have a Swagger UI so you will have to use `curl`, for example.
157+
158+
=== Stopping the application
159+
160+
Stop the application using this command:
161+
162+
```
163+
docker-compose down -v
164+
```

TODO.txt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
eventuate client
2+
3+
sync repo ignores interceptor
4+
error handling ignores options interceptor
5+
6+
tram:
7+
8+
// TODO accidentally returned new Success() and message handler was fine
9+
* mysql image
10+
* logging of sending reply
11+
* in-memory: sending message to channel with no subscribers = error?
12+
* default channel mapping bean
13+
* varags publish domain event
14+
* channel mapping needs to be pushed to lowest-level - messageproducer, messageconsumer
15+
* trameventspublisherconfiguration.class, // todo => tramdomaineventpublisherconfiguration?
16+
17+
exceptions during event delivery don't cause rollback of transaction that records duplicate?
18+
19+
sagas
20+
21+
* mysql image
22+
* logging of sending reply
23+
* logging of sagas actions
24+
25+
26+
--------------------------------
27+
28+
ftgo - big
29+
30+
what functionality:
31+
32+
* Cancel ORder
33+
* Revise order
34+
35+
CQRS:
36+
37+
* Order events,
38+
* Other events
39+
40+
API Gateway
41+
42+
* composition
43+
44+
----
45+
46+
* separate schemas for the services
47+
** tram needs to use an explicit schema
48+
49+
* actual create order request - stupid stuff right now: passing in prices.
50+
** order request should have menuitemid and pricing - need to ask a service to price the order.
51+
*** self (duplicate), ros (preparation - not pricing), rs (ok - except we discussed the need to offload), new orderpricingservice
52+
** do we need to start at the beginning of ordering?? shopping cart?
53+
54+
** saga method throws exception, reported by kafkamessageprocessor, eventuatekafkaconsumer appears to have processed the record. what is the expected behavior??? who stops processing?
55+
56+
** define constants for channels, ?? restaurantorderservice
57+
@transactional
58+
59+
60+
ftgo - misc
61+
62+
* serialization of money
63+
* jpa mapping of enum - e.g. orderstate as name rather than integer
64+
65+
misc
66+
67+
* need static checking of serializability

build-and-restart-service.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#! /bin/bash -e
2+
3+
SNX=${1}
4+
SN=${SNX//-/}
5+
6+
7+
./gradlew :${SNX?}:assemble
8+
docker-compose build ${SN?}
9+
docker-compose up -d ${SN?}
10+
docker-compose logs -f ${SN?}

build-and-test-all.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#! /bin/bash -e
2+
3+
4+
docker-compose down -v
5+
docker-compose up -d --build eventuatelocalcdcservice tramcdcservice
6+
7+
./gradlew -x :ftgo-end-to-end-tests:test build
8+
9+
docker-compose up -d --build
10+
11+
./wait-for-services.sh
12+
13+
./gradlew :ftgo-end-to-end-tests:cleanTest :ftgo-end-to-end-tests:test
14+
15+
docker-compose down -v

build.gradle

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
dependencies {
6+
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
7+
}
8+
}
9+
10+
11+
subprojects {
12+
13+
apply plugin: "java"
14+
15+
repositories {
16+
mavenCentral()
17+
jcenter()
18+
maven {
19+
url "https://dl.bintray.com/eventuateio-oss/eventuate-maven-release"
20+
}
21+
eventuateMavenRepoUrl.split(',').each { repoUrl -> maven { url repoUrl } }
22+
}
23+
24+
}
25+

common-swagger/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dependencies {
2+
compile "io.springfox:springfox-swagger2:2.3.0"
3+
compile "io.springfox:springfox-swagger-ui:2.3.0"
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package net.chrisrichardson.eventstore.examples.customersandorders.commonswagger;
2+
3+
import com.fasterxml.classmate.TypeResolver;
4+
import org.springframework.beans.factory.annotation.Autowired;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.web.context.request.async.DeferredResult;
9+
import springfox.documentation.builders.RequestHandlerSelectors;
10+
import springfox.documentation.schema.WildcardType;
11+
import springfox.documentation.spi.DocumentationType;
12+
import springfox.documentation.spring.web.plugins.Docket;
13+
import springfox.documentation.swagger2.annotations.EnableSwagger2;
14+
15+
import java.util.concurrent.CompletableFuture;
16+
17+
import static springfox.documentation.schema.AlternateTypeRules.newRule;
18+
19+
@Configuration
20+
@EnableSwagger2
21+
public class CommonSwaggerConfiguration {
22+
23+
@Bean
24+
public Docket api() {
25+
return new Docket(DocumentationType.SWAGGER_2)
26+
.select()
27+
.apis(RequestHandlerSelectors.basePackage("net.chrisrichardson.ftgo"))
28+
.build()
29+
.pathMapping("/")
30+
.genericModelSubstitutes(ResponseEntity.class, CompletableFuture.class)
31+
.alternateTypeRules(
32+
newRule(typeResolver.resolve(DeferredResult.class,
33+
typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
34+
typeResolver.resolve(WildcardType.class))
35+
)
36+
.useDefaultResponseMessages(false)
37+
;
38+
}
39+
40+
@Autowired
41+
private TypeResolver typeResolver;
42+
43+
}

0 commit comments

Comments
 (0)