diff --git a/README.md b/README.md index f1b2adda..054b1a1e 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,56 @@ # Springy Store μServices -- This project is a development of a small set of Spring Boot based Microservices projects, that implement cloud-native intuitive, design patterns and coding best practices. +- This project is a development of a small set of **Spring Boot** and **Cloud** based Microservices projects, that implement cloud-native intuitive, Reactive Programming, Event-driven, Microservices design patterns and coding best practices. - The project follows [**CloudNative**](https://www.cncf.io/) recommendations and The [**twelve-factor app**](https://12factor.net/) methodology for building *software-as-a-service apps* to show how μServices should be built and deployed. -- The project is using cutting edge technologies like Docker, Kubernetes, Elasticsearch Stack for logging and monitoring, Java SE 14, MySQL database, MongoDB, TDD, unit, integration & performance testing and Reactive Programming, and many more. +- This project is using cutting edge technologies like Docker, Kubernetes, Elasticsearch Stack for logging and monitoring, Java SE 14, MySQL, and MongoDB databases, all components developed with TDD in mind, covering integration & performance testing, and many more. ------ - I am developing this project as stages, and all such stages are documented under project - **Springy Store μServices** [wiki page](https://github.com/mohamed-taman/Springy-Store-Microservices/wiki). Each of such stage will be a release in its owen, so you can go back and - forward - between releases to see the differences and how adding things solve specific problems we face. + **Springy Store μServices** [wiki page](https://github.com/mohamed-taman/Springy-Store-Microservices/wiki). Each of such stage will be a release in its own, so you can go back and + forward between releases to see the differences and how adding things solve specific problems we face. -For example; in the first stage (1st release) I just created project structure, basic services' skeleton, integration between them, and finally write integration testing as well as semi-automated testing for the whole services' functionality. +For example; in the first stage (1st release) I just created project structure, basic services' skeleton, integration between them, and finally write integration testing as well as semi-automated testing for the whole services' functionality. -At 1st stage the **Recommendation** and **Review** microservices generate local in-memory data - and **Store Service** calls the other three services (*Product*, *Recommendation*, and *Review*) statically to generate client aggregate response for a specific product. Therefore, in: +At the 1st stage the **Recommendation** and **Review** microservices generate local in-memory data and **Store Service** calls the other three services (*Product*, *Recommendation*, and *Review*) statically to generate client aggregate response for a specific product. Therefore, in: - The second stage I will introduce **database integration**, then in (***done***) - The third stage I will introduce **Dockerization** of our services and **docker-compose**, and in (***done***) - The fourth stage I will introduce **service discovery**, and so on. +## System components Structure +Let's explain first the system structure to understand its components: +**Springy Store μService** --> *Parent folder.* +|- **config** --> *All system configuration files* +|- **docs** --> *All docs and diagrams.* +|- **store-base** + |- **store-build-chassis** --> *Super Parent POM, contains all build information* + |- **store-cloud-chassis** --> *Cloud services Parent POM, inherit from build contains all cloud libraries* + |- **store-service-chassis** --> *Parent POM, inherits from cloud contains all microservices common libraries* +|-**store-cloud-infra** + |- **eureka-server** --> *Service discovery server* +|-**store-common** + |- **store-api** --> *API Endpoint and services definitions for all microservices* + |- **store-utils** --> *Common utilities shared between all components* +|-**store-services** + |- **product-service** --> *Product Microservice* + |- **recommendation-service** --> *Recommendation Microservice* + |- **review-service** --> *Review Microservice* + |- **store-service** --> *Store Microservice* +|- **docker-compose.yml** --> *contains all services landscape with RabbitMQ* +|- **docker-compose-kafka.yml** --> *contains all services landscape with more instances working with Kafka with partitions* +|- **docker-compose-partitions.yml** *--> contains all services landscape with more instances working with RabbitMQ with partitions* +|- **run-em-all.sh** *--> Run all microservices in separate mode.* +|- **setup.sh** *--> Install all shared POMs and shared libraries.* +|- **stop-em-all.sh** *--> Stop all services runs in standalone mode.* +|- **test-em-all.sh** *--> This will start all docker compose landscape and test them, then shutdown docker compose containers with test finishes (use switch start stop)* + +Now as we have learned about different system components, then let's start. + ## Getting started The first stage aka (**Release v1.0**) is about creating and implementing a set of project Microservices. -### Creating a Set of Cooperating Microservices +### Creating a Set of Cooperating Microservices (Release v1.0) The following topics are going to be covered in this 1st stage (other stages topics to be documented in a @@ -39,7 +65,7 @@ The following topics are going to be covered in this 1st stage (other stages top - Adding automated tests of microservices in isolation. - Adding semi-automated tests to a microservice landscape. -### System Boundary - μServices Landscape (Release 4) +### System Boundary - μServices Landscape (Release 4.5-Latest) ![System Boundary](docs/stage1/app_ms_landscape.png) @@ -85,11 +111,9 @@ To build and run test cases for each service & shared modules in the project we #### First: Build & Install Shared Dependencies -> This done only for the first time or any new version of shared modules. +> This done only for the first time or any new changes or versions of shared modules and POMs. -To build and install `store-build-chassis`, `store-utils`, `store-api`, `store-chassis` libraries -, from the root - folder `springy-store-microservices` run the following commands: +To build and install `store-build-chassis`, `store-utils`, `store-api`, `store-chassis` libraries, from the root folder `springy-store-microservices` run the following commands: ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices @@ -99,25 +123,27 @@ mohamed.taman@DTLNV8 ~/springy-store-microservices Now you should expect output like this: ```bash -Installing all Springy store core shared modules -................................................ +Installing all Springy store core shared modules & Parent POMs +............................................................... 1- Installing [Parent Build Chassis] module... Done successfully. -2- Installing shared [Services Utilities] module... +2- Installing [Parent Cloud Chassis] module... Done successfully. -3- Installing shared [Services APIs] module... +3- Installing shared [Services Utilities] module... Done successfully. -4- Installing [Services Parent Chassis] module... +4- Installing shared [Services APIs] module... +Done successfully. + +5- Installing [Services Parent Chassis] module... Done successfully. Woohoo, building & installing all project modules are finished successfully. The project is ready for the next step. :) ``` - #### Second: Build & Test Microservices Now it is time to build our **4 microservices** and run each service integration test in isolation by running the following commands: @@ -130,49 +156,47 @@ mohamed.taman@DTLNV8 ~/springy-store-microservices All build commands and test suite for each microservice should run successfully, and the final output should be like this: ```bash -[INFO] ---------------< com.siriusxi.ms.store:store-aggregator >--------------- -[INFO] Building Springy Store Aggregator 1.0-SNAPSHOT [9/9] +---------------< com.siriusxi.ms.store:store-aggregator >--------------- +[INFO] Building Springy Store Aggregator 1.0-SNAPSHOT [11/11] [INFO] --------------------------------[ pom ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ store-aggregator --- [INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary for Springy Store Aggregator 1.0-SNAPSHOT: [INFO] -[INFO] Springy Store Build Chassis ........................ SUCCESS [ 0.276 s] -[INFO] Springy Store APIs ................................. SUCCESS [ 3.920 s] -[INFO] Springy Store Utils ................................ SUCCESS [ 1.508 s] -[INFO] Springy Store Chassis .............................. SUCCESS [ 0.608 s] -[INFO] Store Service ...................................... SUCCESS [ 4.073 s] -[INFO] Product Service .................................... SUCCESS [ 2.710 s] -[INFO] Review Service ..................................... SUCCESS [ 2.633 s] -[INFO] Recommendation Service ............................. SUCCESS [ 2.615 s] -[INFO] Springy Store Aggregator ........................... SUCCESS [ 0.071 s] +[INFO] Springy Store Build Chassis ........................ SUCCESS [ 0.228 s] +[INFO] Springy Store Cloud Chassis ........................ SUCCESS [ 1.257 s] +[INFO] Store APIs ......................................... SUCCESS [ 4.279 s] +[INFO] Store Utils ........................................ SUCCESS [ 1.809 s] +[INFO] Springy Store Chassis .............................. SUCCESS [ 0.857 s] +[INFO] Product Service .................................... SUCCESS [ 13.079 s] +[INFO] Review Service ..................................... SUCCESS [ 9.332 s] +[INFO] Recommendation Service ............................. SUCCESS [ 8.463 s] +[INFO] Store Service ...................................... SUCCESS [ 8.927 s] +[INFO] Eureka Discovery Server ............................ SUCCESS [ 6.536 s] +[INFO] Springy Store Aggregator ........................... SUCCESS [ 0.100 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 18.900 s -[INFO] Finished at: 2020-04-09T01:33:14+02:00 +[INFO] Total time: 55.663 s +[INFO] Finished at: 2020-04-26T03:38:34+02:00 [INFO] ------------------------------------------------------------------------ ``` ### Running Them All #### Using RabbitMQ without the use of partitions -Now it's the time to run all of our reactive Microservices, and it's very simple just run the - following -`docker-compose` commands: +Now it's the time to run all of our reactive Microservices, and it's very simple just run the following `docker-compose` commands: ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices λ docker-compose -p ssm up -d ``` -All the **services**, **databases**, and **messaging service** will run in parallel in detach - mode - (option `-d`), and - command output will print to the console the following: +All the **services**, **databases**, and **messaging service** will run in parallel in detach mode (option `-d`), and command output will print to the console the following: ```bash Creating network "ssm_default" with the default driver +Creating ssm_eureka_1 ... done Creating ssm_mysql_1 ... done Creating ssm_mongodb_1 ... done Creating ssm_rabbitmq_1 ... done @@ -186,23 +210,18 @@ Creating ssm_recommendation_1 ... done You can manually test `Store Service` APIs throughout its **Swagger** interface at the following URL [http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html). #### Access RabbitMQ -In browser point to this URL [http://localhost:5672/](http://localhost:5672/) `username: guest -` and `password: guest`, and you can see all **topics**, **DLQs**, **partitions**, and payload. +In browser point to this URL [http://localhost:5672/](http://localhost:5672/) `username: guest` and `password: guest`, and you can see all **topics**, **DLQs**, **partitions**, and payload. -1. For running 2 instances of each service and using _RabbitMQ with two partitions per topic_, use - the following - `docker-compose` command: +1. For running 2 instances of each service and using _RabbitMQ with two partitions per topic_, use the following `docker-compose` command: ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices λ docker-compose -p ssm -f docker-compose-partitions.yml up -d ``` - 1. To use _Kafka and Zookeeper with two partitions per topic_ run the following - command: - ```bash + 1. To use _Kafka and Zookeeper with two partitions per topic_ run the following command: + ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices λ docker-compose -p ssm -f docker-compose-kafka.yml up -d - ``` - + ``` #### Check All Services Health From Store front Service we can check all the core services health, when you have all the microservices up and running using Docker Compose, @@ -250,7 +269,7 @@ Now it's time to test all the application functionality as one part. To do so ju ```bash mohamed.taman@DTLNV8 ~/springy-store-microservices -λ ./test-em-all.sh +λ ./test-em-all.sh start stop ``` The result will look like this: @@ -305,6 +324,7 @@ Stopping ssm_mongodb_1 ... done Stopping ssm_store_1 ... done Stopping ssm_mysql_1 ... done Stopping ssm_rabbitmq_1 ... done +Stopping ssm_eureka_1 ... done Removing ssm_recommendation_1 ... done Removing ssm_product_1 ... done Removing ssm_review_1 ... done @@ -312,13 +332,12 @@ Removing ssm_mongodb_1 ... done Removing ssm_store_1 ... done Removing ssm_mysql_1 ... done Removing ssm_rabbitmq_1 ... done +Removing ssm_eureka_1 ... done Removing network ssm_default ``` - ### The End Happy coding :) # License Copyright (C) 2017-2020 Mohamed Taman - -Licensed under the MIT License. +Licensed under the MIT License. \ No newline at end of file diff --git a/docker-compose-kafka.yml b/docker-compose-kafka.yml index b43f60d1..665c10c5 100644 --- a/docker-compose-kafka.yml +++ b/docker-compose-kafka.yml @@ -1,6 +1,7 @@ version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ services: + # Start - Core Microservices ## Start - Product service definition ### Instance 1 product: @@ -108,7 +109,19 @@ services: depends_on: - kafka ## End - Store service definition + # End - Core Microservices + # Start - Cloud Infrastructure + ## Start - Eureka Service Discovery definition + eureka: + build: store-cloud-infra/eureka-server + ports: + - "8761:8761" + restart: always + ## End - Eureka Service Discovery definition + # End - Cloud Infrastructure + + # Start - Data and transport Infrastructure ## Start - mongodb database definition ### $ mongo mongodb: @@ -166,4 +179,5 @@ services: environment: - KAFKA_ADVERTISED_HOST_NAME=zookeeper restart: on-failure - ## End - Zookeeper cluster management service \ No newline at end of file + ## End - Zookeeper cluster management service + # End - Data and transport Infrastructure \ No newline at end of file diff --git a/docker-compose-partitions.yml b/docker-compose-partitions.yml index 4013ee8b..8967e9c6 100644 --- a/docker-compose-partitions.yml +++ b/docker-compose-partitions.yml @@ -1,6 +1,7 @@ version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ services: + # Start - Core Microservices ## Start - Product service definition ### Instance 1 product: @@ -94,7 +95,19 @@ services: depends_on: - rabbitmq ## End - Store service definition + # End - Core Microservices + # Start - Cloud Infrastructure + ## Start - Eureka Service Discovery definition + eureka: + build: store-cloud-infra/eureka-server + ports: + - "8761:8761" + restart: always + ## End - Eureka Service Discovery definition + # End - Cloud Infrastructure + + # Start - Data and transport Infrastructure ## Start - mongodb database definition ### $ mongo mongodb: @@ -143,3 +156,4 @@ services: retries: 10 restart: on-failure ## End - RabbitMQ Messaging service + # End - Data and transport Infrastructure \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 0bae5379..dfeb5c27 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ version: '3.7' ## Latest version works with Docker Engine release 18.06.0+ services: + # Start - Core Microservices ## Start - Product service definition product: build: store-services/product-service @@ -42,7 +43,19 @@ services: depends_on: - rabbitmq ## End - Store service definition + # End - Core Microservices + # Start - Cloud Infrastructure + ## Start - Eureka Service Discovery definition + eureka: + build: store-cloud-infra/eureka-server + ports: + - "8761:8761" + restart: on-failure + ## End - Eureka Service Discovery definition + # End - Cloud Infrastructure + + # Start - Data and transport Infrastructure ## Start - mongodb database definition ### $ mongo mongodb: @@ -91,3 +104,4 @@ services: retries: 10 restart: on-failure ## End - RabbitMQ Messaging service + # End - Data and transport Infrastructure diff --git a/docs/stage1/app_ms_landscape.png b/docs/stage1/app_ms_landscape.png index 98452ac4..84105d2c 100644 Binary files a/docs/stage1/app_ms_landscape.png and b/docs/stage1/app_ms_landscape.png differ diff --git a/pom.xml b/pom.xml index d58d4a16..d0410da4 100644 --- a/pom.xml +++ b/pom.xml @@ -17,13 +17,17 @@ + store-base/store-build-chassis + store-base/store-cloud-chassis + store-base/store-service-chassis + store-common/store-api + store-common/store-utils store-services/product-service store-services/review-service store-services/recommendation-service store-services/store-service - store-common/store-api - store-common/store-utils - store-base/store-build-chassis - store-base/store-service-chassis + store-cloud-infra/eureka-server + + diff --git a/setup.sh b/setup.sh index d5531d15..2b63276c 100644 --- a/setup.sh +++ b/setup.sh @@ -1,18 +1,21 @@ #!/usr/bin/env bash ## author: Mohamed Taman -## version: v1.0 -echo -e "\nInstalling all Springy store core shared modules" -echo -e "................................................\n" +## version: v4.5 +echo -e "\nInstalling all Springy store core shared modules & Parent POMs" +echo -e "...............................................................\n" echo "1- Installing [Parent Build Chassis] module..." ./mvnw --quiet clean install -pl store-base/store-build-chassis || exit 126 echo -e "Done successfully.\n" -echo "2- Installing shared [Services Utilities] module..." +echo "2- Installing [Parent Cloud Chassis] module..." +./mvnw --quiet clean install -pl store-base/store-cloud-chassis || exit 126 +echo -e "Done successfully.\n" +echo "3- Installing shared [Services Utilities] module..." ./mvnw --quiet clean install -pl store-common/store-utils || exit 126 echo -e "Done successfully.\n" -echo "3- Installing shared [Services APIs] module..." +echo "4- Installing shared [Services APIs] module..." ./mvnw --quiet clean install -pl store-common/store-api || exit 126 echo -e "Done successfully.\n" -echo "4- Installing [Services Parent Chassis] module..." +echo "5- Installing [Services Parent Chassis] module..." ./mvnw --quiet clean install -pl store-base/store-service-chassis || exit 126 echo -e "Done successfully.\n" diff --git a/store-base/store-build-chassis/pom.xml b/store-base/store-build-chassis/pom.xml index 05900462..289f76ec 100644 --- a/store-base/store-build-chassis/pom.xml +++ b/store-base/store-build-chassis/pom.xml @@ -19,7 +19,7 @@ 14 - Hoxton.RELEASE + Hoxton.SR4 UTF-8 UTF-8 @@ -31,6 +31,7 @@ 3.0.0-M4 1.0.0 2.7 + 1.4.13 3.0.0-SNAPSHOT 1.3.1.Final 1.18.12 @@ -61,7 +62,29 @@ - + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.springframework.boot + spring-boot-properties-migrator + runtime + + org.projectlombok @@ -69,6 +92,7 @@ true + @@ -76,13 +100,6 @@ spring-boot-starter-webflux - - - org.springframework.boot - spring-boot-properties-migrator - runtime - - diff --git a/store-base/store-cloud-chassis/pom.xml b/store-base/store-cloud-chassis/pom.xml new file mode 100644 index 00000000..a20c412b --- /dev/null +++ b/store-base/store-cloud-chassis/pom.xml @@ -0,0 +1,219 @@ + + + 4.0.0 + + com.siriusxi.ms.store + store-build-chassis + 1.0-SNAPSHOT + ../store-build-chassis + + + store-cloud-chassis + 1.0-SNAPSHOT + Springy Store Cloud Chassis + Parent pom project for Springy Cloud infrastructure + pom + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.junit.platform + junit-platform-suite-api + test + + + org.hamcrest + hamcrest-library + test + + + + + + + + + + com.spotify + dockerfile-maven-plugin + ${maven.plugin.dockerfile.version} + + Dockerfile + ${docker.repo.image.prefix}/${project.artifactId} + true + + target/${project.build.finalName}.jar + ${project.version} + ${project.name} + ${maintainer.name} (${maintainer.email}) + + + + + + + + + + + org.codehaus.mojo + properties-maven-plugin + ${maven.plugin.properties.version} + + + initialize + + read-project-properties + + + + false + + ${project.config.file.location} + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + true + + + + + + + build-info + + + + + + + pl.project13.maven + git-commit-id-plugin + + + get-the-git-infos + + revision + + + + validate-the-git-infos + + validateRevision + + package + + + + ${project.basedir}/.git + git + false + true + ${project.build.outputDirectory}/git.properties + + + properties + + + false + false + -dirty + + + + + validating git dirty + + false + false + + + + + + + + + + docker-build + + + ${basedir}/Dockerfile + + + + true + + + + + com.spotify + dockerfile-maven-plugin + + + build-image + package + + build + + + ${docker.image.default.tag} + + + + tag-image + package + + tag + + + ${project.version} + + + + push-image + deploy + + push + + + + + + + + + diff --git a/store-base/store-service-chassis/pom.xml b/store-base/store-service-chassis/pom.xml index 7e50e15a..ed41725a 100644 --- a/store-base/store-service-chassis/pom.xml +++ b/store-base/store-service-chassis/pom.xml @@ -5,9 +5,9 @@ 4.0.0 com.siriusxi.ms.store - store-build-chassis + store-cloud-chassis 1.0-SNAPSHOT - ../store-build-chassis + ../store-cloud-chassis store-service-chassis @@ -16,30 +16,7 @@ Parent pom project for Springy μServices pom - - - 1.4.13 - - - - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - @@ -47,6 +24,7 @@ spring-boot-starter-actuator + org.springframework.cloud @@ -59,26 +37,16 @@ spring-cloud-starter-stream-kafka - - - + - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.hamcrest - hamcrest-library - test + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + io.projectreactor @@ -118,180 +86,4 @@ - - - - - - - com.spotify - dockerfile-maven-plugin - ${maven.plugin.dockerfile.version} - - Dockerfile - ${docker.repo.image.prefix}/${project.artifactId} - true - - target/${project.build.finalName}.jar - ${project.version} - ${project.name} - ${maintainer.name} (${maintainer.email}) - - - - - - - - - - - org.codehaus.mojo - properties-maven-plugin - ${maven.plugin.properties.version} - - - initialize - - read-project-properties - - - - false - - ${project.config.file.location} - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - true - - - - - - - build-info - - - - - - - pl.project13.maven - git-commit-id-plugin - - - get-the-git-infos - - revision - - - - validate-the-git-infos - - validateRevision - - package - - - - ${project.basedir}/.git - git - false - true - ${project.build.outputDirectory}/git.properties - - - properties - - - false - false - -dirty - - - - - validating git dirty - - false - false - - - - - - - - - - docker-build - - - ${basedir}/Dockerfile - - - - true - - - - - com.spotify - dockerfile-maven-plugin - - - build-image - package - - build - - - ${docker.image.default.tag} - - - - tag-image - package - - tag - - - ${project.version} - - - - push-image - deploy - - push - - - - - - - - diff --git a/store-cloud-infra/eureka-server/Dockerfile b/store-cloud-infra/eureka-server/Dockerfile new file mode 100644 index 00000000..ee78850e --- /dev/null +++ b/store-cloud-infra/eureka-server/Dockerfile @@ -0,0 +1,60 @@ +#### Start of builder image +# ------------------------ +# Builder stage to prepare application for final image +FROM openjdk:14-slim-buster as builder +WORKDIR temp + +# Fatjar location, but could be set to different location from command line +ARG JAR_FILE=target/*.jar + +# Copy fat jar file to current image builder +COPY ${JAR_FILE} application.jar + +# Extract the jar file layers +RUN java -Djarmode=layertools -jar --enable-preview application.jar extract + +# Workaround to avoid Copy command failure when directory is not exists. +RUN test ! -d ./snapshot-dependencies \ +&& mkdir snapshot-dependencies \ +&& echo "Directory [snapshot-dependencies] created." + +#### End of builder stage + +#### Start of actual image +# ------------------------ +# Build image based on JDK 14 base image, based on latest debian buster OS +FROM openjdk:14-slim-buster +VOLUME /tmp + +# Set image information, but could be set to different location from command line +ARG IMAGE_VERSION="1.0-SNAPSHOT" +ARG IMAGE_NAME="Eureka Discovery Server" +ARG MAINTAINER="Mohamed Taman " + +LABEL version=${IMAGE_VERSION} name=${IMAGE_NAME} maintainer=${MAINTAINER} + +# Limiting security access to not user root user +RUN addgroup siriusxi && useradd -g siriusxi -ms /bin/bash taman + +# Setting user to current created user +USER taman + +# Set working directory to application folder +WORKDIR /home/taman/application + +# Copy all layers from builder stage to current image +COPY --from=builder temp/dependencies/ ./ +COPY --from=builder temp/snapshot-dependencies/ ./ +COPY --from=builder temp/spring-boot-loader/ ./ +COPY --from=builder temp/application/ ./ + +# Expose current server to port 8080 +EXPOSE 8761 + +ARG JAVA_OPTS="" + +# Run the application with JVM configs if any +ENTRYPOINT ["bash", "-c", \ +"java -server --enable-preview -XX:+UseContainerSupport \ +-XX:+AlwaysActAsServerClassMachine -XX:+UseG1GC -XX:+UseStringDeduplication ${JAVA_OPTS} \ +org.springframework.boot.loader.JarLauncher ${0} ${@}"] \ No newline at end of file diff --git a/store-cloud-infra/eureka-server/pom.xml b/store-cloud-infra/eureka-server/pom.xml new file mode 100644 index 00000000..e8e1045c --- /dev/null +++ b/store-cloud-infra/eureka-server/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + com.siriusxi.ms.store + store-cloud-chassis + 1.0-SNAPSHOT + ../store-base/store-cloud-chassis + + + com.siriusxi.cloud.infra + eureka-server + 1.0-SNAPSHOT + Eureka Discovery Server + Spring Cloud Netflix Eureka Discovery Server, based on Spring boot. + jar + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + + com.github.ben-manes.caffeine + caffeine + + + + diff --git a/store-cloud-infra/eureka-server/src/main/java/com/siriusxi/cloud/infra/eds/EurekaDiscoveryServer.java b/store-cloud-infra/eureka-server/src/main/java/com/siriusxi/cloud/infra/eds/EurekaDiscoveryServer.java new file mode 100644 index 00000000..192541f0 --- /dev/null +++ b/store-cloud-infra/eureka-server/src/main/java/com/siriusxi/cloud/infra/eds/EurekaDiscoveryServer.java @@ -0,0 +1,15 @@ +package com.siriusxi.cloud.infra.eds; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@EnableEurekaServer +@SpringBootApplication +public class EurekaDiscoveryServer { + + public static void main(String[] args) { + SpringApplication.run(EurekaDiscoveryServer.class, args); + } + +} diff --git a/store-cloud-infra/eureka-server/src/main/resources/application.yml b/store-cloud-infra/eureka-server/src/main/resources/application.yml new file mode 100644 index 00000000..d8b853ae --- /dev/null +++ b/store-cloud-infra/eureka-server/src/main/resources/application.yml @@ -0,0 +1,68 @@ +spring: + application: + name: eureka-server + + # As Spring Cloud Ribbon is in maintenance mode. + # It is recommended switching to BlockingLoadBalancerClient instead. + cloud: + loadbalancer: + ribbon: + enabled: false + +server: + port: 8761 + +logging: + level: + com: + netflix: + eureka: OFF + discovery: OFF + +eureka: + environment: Development + datacenter: On Premise + instance: + lease-renewal-interval-in-seconds: 30 + hostname: localhost #eurekaInstance Name + client: + # for development set it to false in order to not register itself to its peer. + Register-with-eureka: false #Do you register yourself with Eureka Server? + Fetch-registry: false #Do not get registration information through eureka + service-url: + defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ + server: + # Make the number of renewals required to prevent an emergency tiny (probably 0) + renewal-percent-threshold: 0.49 + + response-cache-update-interval-ms: 5000 + # Switch off self-preservation. Will turn lease expiration on and evict all instances which + # no longer sent a heartbeat and whose lease has expired. + # Self-preservation is desirable for Eureka clusters and where network outages + # (e.g. between data centers) could be possible. + # Note: the lease validity / expiration is configured in the Eureka _client_ instances + # (see eureka.instance.lease-expiration-duration-in-seconds). + enable-self-preservation: true + + # Make sure this is set to the same value as the lease renewal interval in + # Eureka _client_ instances (or slightly higher), This value is relevant for Eureka's + # calculation of the 'current renewal threshold'. + # Specifically, the following equation is used: + # current renewal threshold = (60s / expected-client-renewal-interval-seconds) * + # renewal-percent-threshold * current number of client instances. + # In this case: + # - for one registered client: 60 / 3 * 0.5 * 1 = 10. + # - for two registered clients: 60 / 3 * 0,5 * 2 = 20. + # As soon as two clients are connected: + expected-client-renewal-interval-seconds: 3 + + # The interval in which the instance eviction task scans for instances with expired leases. + # Given in milliseconds. + eviction-interval-timer-in-ms: 2000 + wait-time-in-ms-when-sync-empty: 0 + +management: + endpoints: + web: + exposure: + include: "*" \ No newline at end of file diff --git a/store-cloud-infra/eureka-server/src/main/resources/config.properties b/store-cloud-infra/eureka-server/src/main/resources/config.properties new file mode 100644 index 00000000..90fca53c --- /dev/null +++ b/store-cloud-infra/eureka-server/src/main/resources/config.properties @@ -0,0 +1,2 @@ +#Just add it empty to git rid of warning message at start up +# archaius.configurationSource.additionalUrls \ No newline at end of file diff --git a/store-cloud-infra/eureka-server/src/test/java/com/siriusxi/cloud/infra/eds/EurekaDiscoveryServerTests.java b/store-cloud-infra/eureka-server/src/test/java/com/siriusxi/cloud/infra/eds/EurekaDiscoveryServerTests.java new file mode 100644 index 00000000..61b3f3d2 --- /dev/null +++ b/store-cloud-infra/eureka-server/src/test/java/com/siriusxi/cloud/infra/eds/EurekaDiscoveryServerTests.java @@ -0,0 +1,36 @@ +package com.siriusxi.cloud.infra.eds; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(webEnvironment = RANDOM_PORT) +class EurekaDiscoveryServerTests { + + @Autowired + private TestRestTemplate testRestTemplate; + + @Test + public void catalogLoads() { + + String expectedReponseBody = "{\"applications\":{\"versions__delta\":\"1\",\"apps__hashcode\":\"\",\"application\":[]}}"; + ResponseEntity entity = testRestTemplate.getForEntity("/eureka/apps", String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals(expectedReponseBody, entity.getBody()); + } + + @Test + public void healthy() { + String expectedReponseBody = "{\"status\":\"UP\"}"; + ResponseEntity entity = testRestTemplate.getForEntity("/actuator/health", String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals(expectedReponseBody, entity.getBody()); + } + +} diff --git a/store-common/store-api/src/main/java/com/siriusxi/ms/store/api/composite/dto/ServiceAddresses.java b/store-common/store-api/src/main/java/com/siriusxi/ms/store/api/composite/dto/ServiceAddresses.java index 2d2da683..9077d050 100644 --- a/store-common/store-api/src/main/java/com/siriusxi/ms/store/api/composite/dto/ServiceAddresses.java +++ b/store-common/store-api/src/main/java/com/siriusxi/ms/store/api/composite/dto/ServiceAddresses.java @@ -9,7 +9,7 @@ @NoArgsConstructor(force = true) @AllArgsConstructor public class ServiceAddresses { - private final String productCompositeService; + private final String storeService; private final String productService; private final String reviewService; private final String recommendationService; diff --git a/store-services/product-service/src/main/resources/application.yaml b/store-services/product-service/src/main/resources/application.yaml index 065c913a..bfc07dce 100644 --- a/store-services/product-service/src/main/resources/application.yaml +++ b/store-services/product-service/src/main/resources/application.yaml @@ -1,6 +1,6 @@ spring: application: - name: product-service + name: product data: mongodb: host: localhost @@ -13,6 +13,12 @@ spring: username: guest password: guest cloud: + # As Spring Cloud Ribbon is in maintenance mode. + # It is recommended switching to BlockingLoadBalancerClient instead. + loadbalancer: + ribbon: + enabled: false + # Event-driven messages Stream config stream: defaultBinder: rabbit default: @@ -67,6 +73,19 @@ management: health: show-details: always +# Service discovery configs +eureka: + client: + healthcheck: + enabled: true + service-url: + defaultZone: http://localhost:8761/eureka/ + initial-instance-info-replication-interval-seconds: 5 + registry-fetch-interval-seconds: 5 + instance: + lease-renewal-interval-in-seconds: 5 + lease-expiration-duration-in-seconds: 5 + # This is a docker specific profile properties # Also profiles could be separated in its owen file # with file name format of "application-docker.yaml" @@ -88,3 +107,8 @@ spring: server: port: 8080 + +eureka: + client: + service-url: + defaultZone: http://eureka:8761/eureka/ diff --git a/store-services/product-service/src/main/resources/config.properties b/store-services/product-service/src/main/resources/config.properties new file mode 100644 index 00000000..90fca53c --- /dev/null +++ b/store-services/product-service/src/main/resources/config.properties @@ -0,0 +1,2 @@ +#Just add it empty to git rid of warning message at start up +# archaius.configurationSource.additionalUrls \ No newline at end of file diff --git a/store-services/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java b/store-services/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java index 15c80139..532cb680 100644 --- a/store-services/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java +++ b/store-services/product-service/src/test/java/com/siriusxi/ms/store/ps/ProductServiceApplicationTests.java @@ -24,7 +24,9 @@ @SpringBootTest( webEnvironment = RANDOM_PORT, - properties = {"spring.data.mongodb.port: 0"}) + properties = { + "spring.data.mongodb.port: 0", + "eureka.client.enabled: false"}) class ProductServiceApplicationTests { private final String BASE_URI = "/products/"; diff --git a/store-services/recommendation-service/src/main/resources/application.yaml b/store-services/recommendation-service/src/main/resources/application.yaml index a71f35ba..59b053b3 100644 --- a/store-services/recommendation-service/src/main/resources/application.yaml +++ b/store-services/recommendation-service/src/main/resources/application.yaml @@ -1,6 +1,6 @@ spring: application: - name: recommendation-service + name: recommendation data: mongodb: host: localhost @@ -13,6 +13,12 @@ spring: username: guest password: guest cloud: + # As Spring Cloud Ribbon is in maintenance mode. + # It is recommended switching to BlockingLoadBalancerClient instead. + loadbalancer: + ribbon: + enabled: false + # Event-driven messages Stream config stream: defaultBinder: rabbit default: @@ -67,6 +73,19 @@ management: health: show-details: always +# Service discovery configs +eureka: + client: + healthcheck: + enabled: true + service-url: + defaultZone: http://localhost:8761/eureka/ + initial-instance-info-replication-interval-seconds: 5 + registry-fetch-interval-seconds: 5 + instance: + lease-renewal-interval-in-seconds: 5 + lease-expiration-duration-in-seconds: 5 + # This is a docker specific profile properties # Also profiles could be separated in its owen file # with file name format of "application-docker.yaml" @@ -88,3 +107,8 @@ spring: server: port: 8080 + +eureka: + client: + service-url: + defaultZone: http://eureka:8761/eureka/ diff --git a/store-services/recommendation-service/src/main/resources/config.properties b/store-services/recommendation-service/src/main/resources/config.properties new file mode 100644 index 00000000..90fca53c --- /dev/null +++ b/store-services/recommendation-service/src/main/resources/config.properties @@ -0,0 +1,2 @@ +#Just add it empty to git rid of warning message at start up +# archaius.configurationSource.additionalUrls \ No newline at end of file diff --git a/store-services/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java b/store-services/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java index 8461b2dc..d063141c 100644 --- a/store-services/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java +++ b/store-services/recommendation-service/src/test/java/com/siriusxi/ms/store/rs/RecommendationServiceApplicationTests.java @@ -27,7 +27,9 @@ @SpringBootTest( webEnvironment = RANDOM_PORT, - properties = {"spring.data.mongodb.port: 0"}) + properties = { + "spring.data.mongodb.port: 0", + "eureka.client.enabled: false"}) class RecommendationServiceApplicationTests { private final String BASE_URI = "/recommendations"; diff --git a/store-services/review-service/src/main/resources/application.yaml b/store-services/review-service/src/main/resources/application.yaml index 900dc7ee..23c19ae9 100644 --- a/store-services/review-service/src/main/resources/application.yaml +++ b/store-services/review-service/src/main/resources/application.yaml @@ -1,6 +1,6 @@ spring: application: - name: review-service + name: review jpa: show-sql: true open-in-view: false @@ -37,6 +37,12 @@ spring: username: guest password: guest cloud: + # As Spring Cloud Ribbon is in maintenance mode. + # It is recommended switching to BlockingLoadBalancerClient instead. + loadbalancer: + ribbon: + enabled: false + # Event-driven messages Stream config stream: defaultBinder: rabbit default: @@ -91,6 +97,19 @@ management: health: show-details: always +# Service discovery configs +eureka: + client: + healthcheck: + enabled: true + service-url: + defaultZone: http://localhost:8761/eureka/ + initial-instance-info-replication-interval-seconds: 5 + registry-fetch-interval-seconds: 5 + instance: + lease-renewal-interval-in-seconds: 5 + lease-expiration-duration-in-seconds: 5 + # This is a docker specific profile properties # Also profiles could be separated in its owen file # with file name format of "application-docker.yaml" @@ -113,4 +132,9 @@ spring: brokers: kafka server: - port: 8080 \ No newline at end of file + port: 8080 + +eureka: + client: + service-url: + defaultZone: http://eureka:8761/eureka/ \ No newline at end of file diff --git a/store-services/review-service/src/main/resources/config.properties b/store-services/review-service/src/main/resources/config.properties new file mode 100644 index 00000000..90fca53c --- /dev/null +++ b/store-services/review-service/src/main/resources/config.properties @@ -0,0 +1,2 @@ +#Just add it empty to git rid of warning message at start up +# archaius.configurationSource.additionalUrls \ No newline at end of file diff --git a/store-services/review-service/src/test/resources/application-test.yaml b/store-services/review-service/src/test/resources/application-test.yaml index 3c5d8fd2..8738f4fd 100644 --- a/store-services/review-service/src/test/resources/application-test.yaml +++ b/store-services/review-service/src/test/resources/application-test.yaml @@ -9,4 +9,10 @@ spring: hibernate: # Strongly recommend to set this property to "none" or with flyway to "validate" in a # production environment! This is okay for test. - ddl-auto: update \ No newline at end of file + ddl-auto: update + +# When running tests on a single microservice, we don't want to depend on +# having the Eureka server up and running. +eureka: + client: + enabled: false \ No newline at end of file diff --git a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/StoreServiceApplication.java b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/StoreServiceApplication.java index 1c1cc1c1..c2cd537d 100644 --- a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/StoreServiceApplication.java +++ b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/StoreServiceApplication.java @@ -2,7 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.web.reactive.function.client.WebClient; import springfox.documentation.swagger2.annotations.EnableSwagger2WebFlux; @SpringBootApplication @@ -12,4 +15,10 @@ public class StoreServiceApplication { public static void main(String[] args) { SpringApplication.run(StoreServiceApplication.class, args); } + + @Bean + @LoadBalanced + public WebClient.Builder loadBalancedWebClientBuilder() { + return WebClient.builder(); + } } diff --git a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java index c683e55b..9c7d1f65 100644 --- a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java +++ b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/config/StoreServiceConfiguration.java @@ -8,7 +8,6 @@ import org.springframework.boot.actuate.health.ReactiveHealthIndicator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; import springfox.documentation.builders.PathSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; @@ -74,11 +73,6 @@ ReactiveHealthContributor coreServices() { return CompositeReactiveHealthContributor.fromMap(allIndicators); } - @Bean - RestTemplate newRestClient() { - return new RestTemplate(); - } - /** * Will exposed on $HOST:$PORT/swagger-ui.html * diff --git a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java index 3e5be5b2..236657c0 100644 --- a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java +++ b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/integration/StoreIntegration.java @@ -38,43 +38,33 @@ @Log4j2 public class StoreIntegration implements ProductService, RecommendationService, ReviewService { - public static final String PRODUCT_ID_QUERY_PARAM = "?productId="; - private final WebClient webClient; + private final String PRODUCT_ID_QUERY_PARAM = "?productId="; + private final WebClient.Builder webClientBuilder; + private WebClient webClient; private final ObjectMapper mapper; private final MessageSources messageSources; private final String productServiceUrl; private final String recommendationServiceUrl; private final String reviewServiceUrl; + @Autowired public StoreIntegration( - WebClient.Builder webClient, - ObjectMapper mapper, + WebClient.Builder webClientBuilder, + ObjectMapper mapper, MessageSources messageSources, - @Value("${app.product-service.host}") String productServiceHost, - @Value("${app.product-service.port}") int productServicePort, - @Value("${app.recommendation-service.host}") String recommendationServiceHost, - @Value("${app.recommendation-service.port}") int recommendationServicePort, - @Value("${app.review-service.host}") String reviewServiceHost, - @Value("${app.review-service.port}") int reviewServicePort) { - - this.webClient = webClient.build(); + @Value("${app.product-service.host}") String productServiceHost, + @Value("${app.recommendation-service.host}") String recommendationServiceHost, + @Value("${app.review-service.host}") String reviewServiceHost) { + + this.webClientBuilder = webClientBuilder; this.mapper = mapper; this.messageSources = messageSources; var http = "http://"; - productServiceUrl = - http.concat(productServiceHost) - .concat(":") - .concat(valueOf(productServicePort)); - recommendationServiceUrl = - http.concat(recommendationServiceHost) - .concat(":") - .concat(valueOf(recommendationServicePort)); - reviewServiceUrl = - http.concat(reviewServiceHost) - .concat(":") - .concat(valueOf(reviewServicePort)); + productServiceUrl = http.concat(productServiceHost); + recommendationServiceUrl = http.concat(recommendationServiceHost); + reviewServiceUrl = http.concat(reviewServiceHost); } @Override @@ -95,7 +85,7 @@ public Mono getProduct(int productId) { log.debug("Will call the getProduct API on URL: {}", url); - return webClient + return getWebClient() .get() .uri(url) .retrieve() @@ -136,7 +126,7 @@ public Flux getRecommendations(int productId) { /* Return an empty result if something goes wrong to make it possible for the composite service to return partial responses */ - return webClient + return getWebClient() .get() .uri(url) .retrieve() @@ -173,7 +163,7 @@ public Flux getReviews(int productId) { /* Return an empty result if something goes wrong to make it possible for the composite service to return partial responses */ - return webClient + return getWebClient() .get() .uri(url) .retrieve() @@ -201,10 +191,17 @@ public Mono getReviewHealth() { return getHealth(reviewServiceUrl); } + private WebClient getWebClient() { + if (webClient == null) { + webClient = webClientBuilder.build(); + } + return webClient; + } + private Mono getHealth(String url) { url += "/actuator/health"; log.debug("Will call the Health API on URL: {}", url); - return webClient.get().uri(url).retrieve().bodyToMono(String.class) + return getWebClient().get().uri(url).retrieve().bodyToMono(String.class) .map(s -> new Health.Builder().up().build()) .onErrorResume(ex -> Mono.just(new Health.Builder().down(ex).build())) .log(); diff --git a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java index d8ea44d8..ae239aed 100644 --- a/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java +++ b/store-services/store-service/src/main/java/com/siriusxi/ms/store/pcs/service/StoreServiceImpl.java @@ -155,9 +155,9 @@ private ProductAggregate createProductAggregate( // 4. Create info regarding the involved microservices addresses String productAddress = product.getServiceAddress(); String reviewAddress = - (reviews != null && reviews.size() > 0) ? reviews.get(0).getServiceAddress() : ""; + (reviews != null && ! reviews.isEmpty()) ? reviews.get(0).getServiceAddress() : ""; String recommendationAddress = - (recommendations != null && recommendations.size() > 0) + (recommendations != null && ! recommendations.isEmpty()) ? recommendations.get(0).getServiceAddress() : ""; ServiceAddresses serviceAddresses = diff --git a/store-services/store-service/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/store-services/store-service/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 2833250c..f2ca1550 100644 --- a/store-services/store-service/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/store-services/store-service/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -5,31 +5,16 @@ "type": "java.lang.String", "description": "Description for app.product-service.host." }, - { - "name": "app.product-service.port", - "type": "java.lang.Integer", - "description": "Description for app.product-service.port." - }, { "name": "app.recommendation-service.host", "type": "java.lang.String", "description": "Description for app.recommendation-service.host." }, - { - "name": "app.recommendation-service.port", - "type": "java.lang.Integer", - "description": "Description for app.recommendation-service.port." - }, { "name": "app.review-service.host", "type": "java.lang.String", "description": "Description for app.review-service.host." }, - { - "name": "app.review-service.port", - "type": "java.lang.Integer", - "description": "Description for app.review-service.port." - }, { "name": "api.common.version", "type": "java.lang.String", diff --git a/store-services/store-service/src/main/resources/application.yaml b/store-services/store-service/src/main/resources/application.yaml index 60c8ce70..cac83bb9 100644 --- a/store-services/store-service/src/main/resources/application.yaml +++ b/store-services/store-service/src/main/resources/application.yaml @@ -1,8 +1,14 @@ spring: application: name: store-service - cloud: + # As Spring Cloud Ribbon is in maintenance mode. + # It is recommended switching to BlockingLoadBalancerClient instead. + loadbalancer: + ribbon: + enabled: false + # Massaging provider configurations + ## Event-driven messages Stream config stream: defaultBinder: rabbit default: @@ -24,22 +30,40 @@ spring: binder: brokers: 127.0.0.1 defaultBrokerPort: 9092 - rabbitmq: host: 127.0.0.1 port: 5672 username: guest password: guest +# Service discovery configs +eureka: + client: + healthcheck: + enabled: true + service-url: + defaultZone: http://localhost:8761/eureka/ + initial-instance-info-replication-interval-seconds: 5 + registry-fetch-interval-seconds: 5 + instance: + lease-renewal-interval-in-seconds: 5 + lease-expiration-duration-in-seconds: 5 + +ribbon.server-list-refresh-interval: 5000 +ribbon.NFLoadBalancerPingInterval: 5 + +# Server configs server: port: 9080 +# Logging configs logging: level: web: DEBUG root: INFO com.siriusxi.ms.store: DEBUG +# Application health and information management management: info: git: @@ -57,14 +81,11 @@ management: # Custom configurations app: product-service: - host: localhost - port: 9081 + host: product recommendation-service: - host: localhost - port: 9082 + host: recommendation review-service: - host: localhost - port: 9083 + host: review # Swagger properties api: @@ -141,13 +162,7 @@ spring: server: port: 8080 -app: - product-service: - host: product - port: 8080 - recommendation-service: - host: recommendation - port: 8080 - review-service: - host: review - port: 8080 \ No newline at end of file +eureka: + client: + service-url: + defaultZone: http://eureka:8761/eureka/ \ No newline at end of file diff --git a/store-services/store-service/src/main/resources/config.properties b/store-services/store-service/src/main/resources/config.properties new file mode 100644 index 00000000..145fbafe --- /dev/null +++ b/store-services/store-service/src/main/resources/config.properties @@ -0,0 +1,2 @@ +# Just add it empty to git rid of warning message at start up +# archaius.configurationSource.additionalUrls \ No newline at end of file diff --git a/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java b/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java index 90a279f9..df78471f 100644 --- a/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java +++ b/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/MessagingTests.java @@ -32,7 +32,9 @@ import static org.springframework.cloud.stream.test.matcher.MessageQueueMatcher.receivesPayloadThat; import static org.springframework.http.HttpStatus.OK; -@SpringBootTest(webEnvironment = RANDOM_PORT) +@SpringBootTest( + webEnvironment = RANDOM_PORT, + properties = {"eureka.client.enabled: false"}) class MessagingTests { public static final String BASE_URL = "/store/api/v1/products/"; diff --git a/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java b/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java index ed55d7bb..0ba6ae51 100644 --- a/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java +++ b/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceApplicationTests.java @@ -23,7 +23,9 @@ import static org.springframework.http.HttpStatus.*; import static org.springframework.http.MediaType.APPLICATION_JSON; -@SpringBootTest(webEnvironment = RANDOM_PORT) +@SpringBootTest( + webEnvironment = RANDOM_PORT, + properties = {"eureka.client.enabled: false"}) class StoreServiceApplicationTests { public static final String BASE_URL = "/store/api/v1/products/"; diff --git a/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceTestingSuite.java b/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceTestingSuite.java new file mode 100644 index 00000000..d82c67db --- /dev/null +++ b/store-services/store-service/src/test/java/com/siriusxi/ms/store/pcs/StoreServiceTestingSuite.java @@ -0,0 +1,8 @@ +package com.siriusxi.ms.store.pcs; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.SuiteDisplayName; + +@SuiteDisplayName("Store Service Testing Suite") +@SelectClasses(value = {StoreServiceApplicationTests.class, MessagingTests.class}) +public class StoreServiceTestingSuite {}