├── .gitignore
├── README.md
├── amqp
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── amigoscode
│ └── amqp
│ ├── RabbitMQConfig.java
│ └── RabbitMQMessageProducer.java
├── apigw
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── amigoscode
│ │ └── apigw
│ │ └── ApiGWApplication.java
│ └── resources
│ ├── application-docker.yml
│ ├── application.yml
│ └── banner.txt
├── clients
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── amigoscode
│ │ └── clients
│ │ ├── fraud
│ │ ├── FraudCheckResponse.java
│ │ └── FraudClient.java
│ │ └── notification
│ │ ├── NotificationClient.java
│ │ └── NotificationRequest.java
│ └── resources
│ ├── clients-default.properties
│ ├── clients-docker.properties
│ └── clients-kube.properties
├── customer
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── amigoscode
│ │ └── customer
│ │ ├── Customer.java
│ │ ├── CustomerApplication.java
│ │ ├── CustomerController.java
│ │ ├── CustomerRegistrationRequest.java
│ │ ├── CustomerRepository.java
│ │ └── CustomerService.java
│ └── resources
│ ├── application-docker.yml
│ ├── application-kube.yml
│ ├── application.yml
│ └── banner.txt
├── diagrams.drawio
├── docker-compose.yml
├── eureka-server
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── amigoscode
│ │ └── eurekaserver
│ │ └── EurekaServerApplication.java
│ └── resources
│ ├── application-docker.yml
│ ├── application.yml
│ └── banner.txt
├── fraud
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── amigoscode
│ │ └── fraud
│ │ ├── FraudApplication.java
│ │ ├── FraudCheckHistory.java
│ │ ├── FraudCheckHistoryRepository.java
│ │ ├── FraudCheckService.java
│ │ └── FraudController.java
│ └── resources
│ ├── application-docker.yml
│ ├── application-kube.yml
│ ├── application.yml
│ └── banner.txt
├── k8s
└── minikube
│ ├── bootstrap
│ ├── postgres
│ │ ├── configmap.yml
│ │ ├── service.yml
│ │ ├── statefulset.yml
│ │ └── volume.yml
│ ├── rabbitmq
│ │ ├── README.md
│ │ ├── configmap.yaml
│ │ ├── rbac.yaml
│ │ ├── services.yaml
│ │ └── statefulset.yaml
│ └── zipkin
│ │ ├── service.yml
│ │ └── statefulset.yml
│ └── services
│ ├── customer
│ ├── deployment.yml
│ └── service.yml
│ ├── fraud
│ ├── deployment.yml
│ └── service.yml
│ └── notification
│ ├── deployment.yml
│ └── service.yml
├── notification
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── amigoscode
│ │ └── notification
│ │ ├── Notification.java
│ │ ├── NotificationApplication.java
│ │ ├── NotificationConfig.java
│ │ ├── NotificationController.java
│ │ ├── NotificationRepository.java
│ │ ├── NotificationService.java
│ │ └── rabbitmq
│ │ └── NotificationConsumer.java
│ └── resources
│ ├── application-docker.yml
│ ├── application-kube.yml
│ ├── application.yml
│ └── banner.txt
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | **/target/
4 | !.mvn/wrapper/maven-wrapper.jar
5 | !**/src/main/**/target/
6 | !**/src/test/**/target/
7 | .idea/
8 |
9 | ### STS ###
10 | .apt_generated
11 | .classpath
12 | .factorypath
13 | .project
14 | .settings
15 | .springBeans
16 | .sts4-cache
17 |
18 | ### IntelliJ IDEA ###
19 | .idea
20 | *.iws
21 | *.iml
22 | *.ipr
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Microservices
2 | 
3 |
4 |
--------------------------------------------------------------------------------
/amqp/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | amigosservices
7 | com.amigoscode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | amqp
13 |
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-starter-amqp
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/amqp/src/main/java/com/amigoscode/amqp/RabbitMQConfig.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.amqp;
2 |
3 | import lombok.AllArgsConstructor;
4 | import org.springframework.amqp.core.AmqpTemplate;
5 | import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
6 | import org.springframework.amqp.rabbit.connection.ConnectionFactory;
7 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
8 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
9 | import org.springframework.amqp.support.converter.MessageConverter;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 |
13 | @Configuration
14 | @AllArgsConstructor
15 | public class RabbitMQConfig {
16 |
17 | private final ConnectionFactory connectionFactory;
18 |
19 | @Bean
20 | public AmqpTemplate amqpTemplate() {
21 | RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
22 | rabbitTemplate.setMessageConverter(jacksonConverter());
23 | return rabbitTemplate;
24 | }
25 |
26 | @Bean
27 | public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory() {
28 | SimpleRabbitListenerContainerFactory factory =
29 | new SimpleRabbitListenerContainerFactory();
30 | factory.setConnectionFactory(connectionFactory);
31 | factory.setMessageConverter(jacksonConverter());
32 | return factory;
33 | }
34 |
35 | @Bean
36 | public MessageConverter jacksonConverter() {
37 | MessageConverter jackson2JsonMessageConverter =
38 | new Jackson2JsonMessageConverter();
39 | return jackson2JsonMessageConverter;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/amqp/src/main/java/com/amigoscode/amqp/RabbitMQMessageProducer.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.amqp;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.amqp.core.AmqpTemplate;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | @Slf4j
10 | @AllArgsConstructor
11 | public class RabbitMQMessageProducer {
12 |
13 | private final AmqpTemplate amqpTemplate;
14 |
15 | public void publish(Object payload, String exchange, String routingKey) {
16 | log.info("Publishing to {} using routingKey {}. Payload: {}", exchange, routingKey, payload);
17 | amqpTemplate.convertAndSend(exchange, routingKey, payload);
18 | log.info("Published to {} using routingKey {}. Payload: {}", exchange, routingKey, payload);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/apigw/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | amigosservices
7 | com.amigoscode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | apigw
13 |
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-maven-plugin
19 |
20 |
21 |
22 |
23 |
24 |
25 | build-docker-image
26 |
27 |
28 |
29 | com.google.cloud.tools
30 | jib-maven-plugin
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.cloud
40 | spring-cloud-starter-gateway
41 |
42 |
43 | org.springframework.cloud
44 | spring-cloud-starter-netflix-eureka-client
45 |
46 |
47 | org.springframework.cloud
48 | spring-cloud-starter-sleuth
49 |
50 |
51 | org.springframework.cloud
52 | spring-cloud-sleuth-zipkin
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/apigw/src/main/java/com/amigoscode/apigw/ApiGWApplication.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.apigw;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6 |
7 | @EnableEurekaClient
8 | @SpringBootApplication
9 | public class ApiGWApplication {
10 | public static void main(String[] args) {
11 | SpringApplication.run(ApiGWApplication.class, args);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/apigw/src/main/resources/application-docker.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8083
3 |
4 | spring:
5 | application:
6 | name: api-gateway
7 | zipkin:
8 | base-url: http://zipkin:9411
9 | cloud:
10 | gateway:
11 | routes:
12 | - id: customer
13 | uri: lb://CUSTOMER
14 | predicates:
15 | - Path=/api/v1/customers/**
16 |
17 | eureka:
18 | client:
19 | service-url:
20 | defaultZone: http://eureka-server:8761/eureka
21 | fetch-registry: true
22 | register-with-eureka: true
--------------------------------------------------------------------------------
/apigw/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8083
3 |
4 | spring:
5 | application:
6 | name: api-gateway
7 | zipkin:
8 | base-url: http://localhost:9411
9 | cloud:
10 | gateway:
11 | routes:
12 | - id: customer
13 | uri: lb://CUSTOMER
14 | predicates:
15 | - Path=/api/v1/customers/**
16 |
17 | eureka:
18 | client:
19 | service-url:
20 | defaultZone: http://localhost:8761/eureka
21 | fetch-registry: true
22 | register-with-eureka: true
--------------------------------------------------------------------------------
/apigw/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ,---. ,------. ,--. ,----. ,--. ,--.
2 | / O \ | .--. ' | | ' .-./ | | | |
3 | | .-. | | '--' | | | | | .---. | |.'.| |
4 | | | | | | | --' | | ' '--' | | ,'. |
5 | `--' `--' `--' `--' `------' '--' '--'
6 |
7 | ${application.title} ${application.version}
8 | Powered by Spring Boot ${spring-boot.version}
--------------------------------------------------------------------------------
/clients/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | amigosservices
7 | com.amigoscode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | clients
13 |
14 |
--------------------------------------------------------------------------------
/clients/src/main/java/com/amigoscode/clients/fraud/FraudCheckResponse.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.clients.fraud;
2 |
3 | public record FraudCheckResponse(Boolean isFraudster) {
4 | }
5 |
--------------------------------------------------------------------------------
/clients/src/main/java/com/amigoscode/clients/fraud/FraudClient.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.clients.fraud;
2 |
3 | import org.springframework.cloud.openfeign.FeignClient;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.PathVariable;
6 |
7 | @FeignClient(
8 | name = "fraud",
9 | url = "${clients.fraud.url}"
10 | )
11 | public interface FraudClient {
12 |
13 | @GetMapping(path = "api/v1/fraud-check/{customerId}")
14 | FraudCheckResponse isFraudster(
15 | @PathVariable("customerId") Integer customerId);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/clients/src/main/java/com/amigoscode/clients/notification/NotificationClient.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.clients.notification;
2 |
3 | import org.springframework.cloud.openfeign.FeignClient;
4 | import org.springframework.web.bind.annotation.PostMapping;
5 |
6 | @FeignClient(
7 | name = "notification",
8 | url = "${clients.notification.url}"
9 | )
10 | public interface NotificationClient {
11 |
12 | @PostMapping("api/v1/notification")
13 | void sendNotification(NotificationRequest notificationRequest);
14 | }
15 |
--------------------------------------------------------------------------------
/clients/src/main/java/com/amigoscode/clients/notification/NotificationRequest.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.clients.notification;
2 |
3 | public record NotificationRequest(
4 | Integer toCustomerId,
5 | String toCustomerName,
6 | String message
7 | ) {
8 | }
9 |
--------------------------------------------------------------------------------
/clients/src/main/resources/clients-default.properties:
--------------------------------------------------------------------------------
1 | clients.customer.url=http://localhost:8080
2 | clients.fraud.url=http://localhost:8081
3 | clients.notification.url=http://localhost:8082
--------------------------------------------------------------------------------
/clients/src/main/resources/clients-docker.properties:
--------------------------------------------------------------------------------
1 | clients.customer.url=http://customer:8080
2 | clients.fraud.url=http://fraud:8081
3 | clients.notification.url=http://notification:8082
--------------------------------------------------------------------------------
/clients/src/main/resources/clients-kube.properties:
--------------------------------------------------------------------------------
1 | clients.customer.url=http://customer:8080
2 | clients.fraud.url=http://fraud:8081
3 | clients.notification.url=http://notification:8082
--------------------------------------------------------------------------------
/customer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | com.amigoscode
7 | amigosservices
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | customer
13 |
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-maven-plugin
19 |
20 |
21 |
22 |
23 |
24 |
25 | build-docker-image
26 |
27 |
28 |
29 | com.google.cloud.tools
30 | jib-maven-plugin
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-data-jpa
45 |
46 |
47 | org.postgresql
48 | postgresql
49 | runtime
50 |
51 |
52 | org.springframework.cloud
53 | spring-cloud-starter-netflix-eureka-client
54 |
55 |
56 | org.springframework.cloud
57 | spring-cloud-starter-sleuth
58 |
59 |
60 | org.springframework.cloud
61 | spring-cloud-sleuth-zipkin
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-amqp
66 |
67 |
68 | com.amigoscode
69 | amqp
70 | 1.0-SNAPSHOT
71 | compile
72 |
73 |
74 | com.amigoscode
75 | clients
76 | 1.0-SNAPSHOT
77 | compile
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/customer/src/main/java/com/amigoscode/customer/Customer.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.customer;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import javax.persistence.Entity;
9 | import javax.persistence.GeneratedValue;
10 | import javax.persistence.Id;
11 | import javax.persistence.SequenceGenerator;
12 | import javax.persistence.GenerationType;
13 |
14 | @Data
15 | @Builder
16 | @AllArgsConstructor
17 | @NoArgsConstructor
18 | @Entity
19 | public class Customer {
20 |
21 | @Id
22 | @SequenceGenerator(
23 | name = "customer_id_sequence",
24 | sequenceName = "customer_id_sequence"
25 | )
26 | @GeneratedValue(
27 | strategy = GenerationType.SEQUENCE,
28 | generator = "customer_id_sequence"
29 | )
30 | private Integer id;
31 | private String firstName;
32 | private String lastName;
33 | private String email;
34 | }
35 |
--------------------------------------------------------------------------------
/customer/src/main/java/com/amigoscode/customer/CustomerApplication.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.customer;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6 | import org.springframework.cloud.openfeign.EnableFeignClients;
7 | import org.springframework.context.annotation.PropertySource;
8 | import org.springframework.context.annotation.PropertySources;
9 |
10 | @SpringBootApplication(
11 | scanBasePackages = {
12 | "com.amigoscode.customer",
13 | "com.amigoscode.amqp",
14 | }
15 | )
16 | @EnableEurekaClient
17 | @EnableFeignClients(
18 | basePackages = "com.amigoscode.clients"
19 | )
20 | @PropertySources({
21 | @PropertySource("classpath:clients-${spring.profiles.active}.properties")
22 | })
23 | public class CustomerApplication {
24 | public static void main(String[] args) {
25 | SpringApplication.run(CustomerApplication.class, args);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/customer/src/main/java/com/amigoscode/customer/CustomerController.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.customer;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.web.bind.annotation.PostMapping;
6 | import org.springframework.web.bind.annotation.RequestBody;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | @Slf4j
11 | @RestController
12 | @RequestMapping("api/v1/customers")
13 | @AllArgsConstructor
14 | public class CustomerController {
15 |
16 | private final CustomerService customerService;
17 |
18 | @PostMapping
19 | public void registerCustomer(@RequestBody CustomerRegistrationRequest customerRegistrationRequest) {
20 | log.info("new customer registration {}", customerRegistrationRequest);
21 | customerService.registerCustomer(customerRegistrationRequest);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/customer/src/main/java/com/amigoscode/customer/CustomerRegistrationRequest.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.customer;
2 |
3 | public record CustomerRegistrationRequest(
4 | String firstName,
5 | String lastName,
6 | String email) {
7 | }
8 |
--------------------------------------------------------------------------------
/customer/src/main/java/com/amigoscode/customer/CustomerRepository.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.customer;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | public interface CustomerRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/customer/src/main/java/com/amigoscode/customer/CustomerService.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.customer;
2 |
3 | import com.amigoscode.amqp.RabbitMQMessageProducer;
4 | import com.amigoscode.clients.fraud.FraudCheckResponse;
5 | import com.amigoscode.clients.fraud.FraudClient;
6 | import com.amigoscode.clients.notification.NotificationClient;
7 | import com.amigoscode.clients.notification.NotificationRequest;
8 | import lombok.AllArgsConstructor;
9 | import org.springframework.stereotype.Service;
10 |
11 | @Service
12 | @AllArgsConstructor
13 | public class CustomerService {
14 |
15 | private final CustomerRepository customerRepository;
16 | private final FraudClient fraudClient;
17 | private final RabbitMQMessageProducer rabbitMQMessageProducer;
18 |
19 | public void registerCustomer(CustomerRegistrationRequest request) {
20 | Customer customer = Customer.builder()
21 | .firstName(request.firstName())
22 | .lastName(request.lastName())
23 | .email(request.email())
24 | .build();
25 | // todo: check if email valid
26 | // todo: check if email not taken
27 | customerRepository.saveAndFlush(customer);
28 |
29 | FraudCheckResponse fraudCheckResponse =
30 | fraudClient.isFraudster(customer.getId());
31 |
32 | if (fraudCheckResponse.isFraudster()) {
33 | throw new IllegalStateException("fraudster");
34 | }
35 |
36 | NotificationRequest notificationRequest = new NotificationRequest(
37 | customer.getId(),
38 | customer.getEmail(),
39 | String.format("Hi %s, welcome to Amigoscode...",
40 | customer.getFirstName())
41 | );
42 | rabbitMQMessageProducer.publish(
43 | notificationRequest,
44 | "internal.exchange",
45 | "internal.notification.routing-key"
46 | );
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/customer/src/main/resources/application-docker.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | spring:
4 | application:
5 | name: customer
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://postgres:5432/customer
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://zipkin:9411
20 | rabbitmq:
21 | addresses: rabbitmq:5672
22 | eureka:
23 | client:
24 | service-url:
25 | defaultZone: http://eureka-server:8761/eureka
26 | fetch-registry: true
27 | register-with-eureka: true
28 | enabled: false
29 |
30 |
--------------------------------------------------------------------------------
/customer/src/main/resources/application-kube.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | spring:
4 | application:
5 | name: customer
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://postgres:5432/customer
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://zipkin:9411
20 | rabbitmq:
21 | addresses: rabbitmq:5672
22 | eureka:
23 | client:
24 | service-url:
25 | defaultZone: http://eureka-server:8761/eureka
26 | fetch-registry: true
27 | register-with-eureka: true
28 | enabled: false
29 |
30 |
--------------------------------------------------------------------------------
/customer/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | spring:
4 | application:
5 | name: customer
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://localhost:5432/customer
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://localhost:9411
20 | rabbitmq:
21 | addresses: localhost:5672
22 | profiles:
23 | active: default
24 | eureka:
25 | client:
26 | service-url:
27 | defaultZone: http://localhost:8761/eureka
28 | fetch-registry: true
29 | register-with-eureka: true
30 | enabled: true
31 |
32 |
--------------------------------------------------------------------------------
/customer/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ,-----. ,--.
2 | ' .--./ ,--.,--. ,---. ,-' '-. ,---. ,--,--,--. ,---. ,--.--.
3 | | | | || | ( .-' '-. .-' | .-. | | | | .-. : | .--'
4 | ' '--'\ ' '' ' .-' `) | | ' '-' ' | | | | \ --. | |
5 | `-----' `----' `----' `--' `---' `--`--`--' `----' `--'
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | postgres:
3 | container_name: postgres
4 | image: postgres
5 | environment:
6 | POSTGRES_USER: amigoscode
7 | POSTGRES_PASSWORD: password
8 | PGDATA: /data/postgres
9 | volumes:
10 | - postgres:/data/postgres
11 | ports:
12 | - "5432:5432"
13 | networks:
14 | - postgres
15 | restart: unless-stopped
16 | pgadmin:
17 | container_name: pgadmin
18 | image: dpage/pgadmin4
19 | environment:
20 | PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org}
21 | PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin}
22 | PGADMIN_CONFIG_SERVER_MODE: 'False'
23 | volumes:
24 | - pgadmin:/var/lib/pgadmin
25 | ports:
26 | - "5050:80"
27 | networks:
28 | - postgres
29 | restart: unless-stopped
30 | zipkin:
31 | image: openzipkin/zipkin
32 | container_name: zipkin
33 | ports:
34 | - "9411:9411"
35 | networks:
36 | - spring
37 | rabbitmq:
38 | image: rabbitmq:3.9.11-management-alpine
39 | container_name: rabbitmq
40 | ports:
41 | - "5672:5672"
42 | - "15672:15672"
43 | networks:
44 | - spring
45 | # eureka-server:
46 | # image: amigoscode/eureka-server:latest
47 | # container_name: eureka-server
48 | # ports:
49 | # - "8761:8761"
50 | # environment:
51 | # - SPRING_PROFILES_ACTIVE=docker
52 | # networks:
53 | # - spring
54 | # depends_on:
55 | # - zipkin
56 | # apigw:
57 | # image: amigoscode/apigw:latest
58 | # container_name: apigw
59 | # ports:
60 | # - "8083:8083"
61 | # environment:
62 | # - SPRING_PROFILES_ACTIVE=docker
63 | # networks:
64 | # - spring
65 | # depends_on:
66 | # - zipkin
67 | # - eureka-server
68 | # customer:
69 | # image: amigoscode/customer:latest
70 | # container_name: customer
71 | # ports:
72 | # - "8080:8080"
73 | # environment:
74 | # - SPRING_PROFILES_ACTIVE=docker
75 | # networks:
76 | # - spring
77 | # - postgres
78 | # depends_on:
79 | # - zipkin
80 | # - postgres
81 | # - rabbitmq
82 | # fraud:
83 | # image: amigoscode/fraud:latest
84 | # container_name: fraud
85 | # ports:
86 | # - "8081:8081"
87 | # environment:
88 | # - SPRING_PROFILES_ACTIVE=docker
89 | # networks:
90 | # - spring
91 | # - postgres
92 | # depends_on:
93 | # - zipkin
94 | # - postgres
95 | # - rabbitmq
96 | # notification:
97 | # image: amigoscode/notification:latest
98 | # container_name: notification
99 | # ports:
100 | # - "8082:8082"
101 | # environment:
102 | # - SPRING_PROFILES_ACTIVE=docker
103 | # networks:
104 | # - spring
105 | # - postgres
106 | # depends_on:
107 | # - zipkin
108 | # - postgres
109 | # - rabbitmq
110 | networks:
111 | postgres:
112 | driver: bridge
113 | spring:
114 | driver: bridge
115 |
116 | volumes:
117 | postgres:
118 | pgadmin:
--------------------------------------------------------------------------------
/eureka-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | amigosservices
7 | com.amigoscode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | eureka-server
13 |
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-maven-plugin
19 |
20 |
21 |
22 |
23 |
24 |
25 | build-docker-image
26 |
27 |
28 |
29 | com.google.cloud.tools
30 | jib-maven-plugin
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.cloud
40 | spring-cloud-starter-netflix-eureka-server
41 |
42 |
43 | org.springframework.cloud
44 | spring-cloud-starter-sleuth
45 |
46 |
47 | org.springframework.cloud
48 | spring-cloud-sleuth-zipkin
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/eureka-server/src/main/java/com/amigoscode/eurekaserver/EurekaServerApplication.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.eurekaserver;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
6 |
7 | @SpringBootApplication
8 | @EnableEurekaServer
9 | public class EurekaServerApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(EurekaServerApplication.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/eureka-server/src/main/resources/application-docker.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: eureka-server
4 | zipkin:
5 | base-url: http://zipkin:9411
6 |
7 | server:
8 | port: 8761
9 |
10 | eureka:
11 | client:
12 | fetch-registry: false
13 | register-with-eureka: false
14 |
--------------------------------------------------------------------------------
/eureka-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: eureka-server
4 | zipkin:
5 | base-url: http://localhost:9411
6 |
7 | server:
8 | port: 8761
9 |
10 | eureka:
11 | client:
12 | fetch-registry: false
13 | register-with-eureka: false
14 |
--------------------------------------------------------------------------------
/eureka-server/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ,------. ,--. ,---.
2 | | .---' ,--.,--. ,--.--. ,---. | |,-. ,--,--. ' .-' ,---. ,--.--. ,--. ,--. ,---. ,--.--.
3 | | `--, | || | | .--' | .-. : | / ' ,-. | `. `-. | .-. : | .--' \ `' / | .-. : | .--'
4 | | `---. ' '' ' | | \ --. | \ \ \ '-' | .-' | \ --. | | \ / \ --. | |
5 | `------' `----' `--' `----' `--'`--' `--`--' `-----' `----' `--' `--' `----' `--'
--------------------------------------------------------------------------------
/fraud/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | amigosservices
7 | com.amigoscode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | fraud
13 |
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-maven-plugin
19 |
20 |
21 |
22 |
23 |
24 |
25 | build-docker-image
26 |
27 |
28 |
29 | com.google.cloud.tools
30 | jib-maven-plugin
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-data-jpa
45 |
46 |
47 | org.postgresql
48 | postgresql
49 | runtime
50 |
51 |
52 | org.springframework.cloud
53 | spring-cloud-starter-netflix-eureka-client
54 |
55 |
56 | org.springframework.cloud
57 | spring-cloud-starter-sleuth
58 |
59 |
60 | org.springframework.cloud
61 | spring-cloud-sleuth-zipkin
62 |
63 |
64 | com.amigoscode
65 | clients
66 | 1.0-SNAPSHOT
67 | compile
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/fraud/src/main/java/com/amigoscode/fraud/FraudApplication.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.fraud;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6 | import org.springframework.context.annotation.PropertySource;
7 | import org.springframework.context.annotation.PropertySources;
8 |
9 | @SpringBootApplication
10 | @EnableEurekaClient
11 | @PropertySources({
12 | @PropertySource("classpath:clients-${spring.profiles.active}.properties")
13 | })
14 | public class FraudApplication {
15 | public static void main(String[] args) {
16 | SpringApplication.run(FraudApplication.class, args);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/fraud/src/main/java/com/amigoscode/fraud/FraudCheckHistory.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.fraud;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import javax.persistence.Entity;
9 | import javax.persistence.GeneratedValue;
10 | import javax.persistence.Id;
11 | import javax.persistence.SequenceGenerator;
12 | import javax.persistence.GenerationType;
13 |
14 | import java.time.LocalDateTime;
15 |
16 | @Data
17 | @Builder
18 | @AllArgsConstructor
19 | @NoArgsConstructor
20 | @Entity
21 | public class FraudCheckHistory {
22 | @Id
23 | @SequenceGenerator(
24 | name = "fraud_id_sequence",
25 | sequenceName = "fraud_id_sequence"
26 | )
27 | @GeneratedValue(
28 | strategy = GenerationType.SEQUENCE,
29 | generator = "fraud_id_sequence"
30 | )
31 | private Integer id;
32 | private Integer customerId;
33 | private Boolean isFraudster;
34 | private LocalDateTime createdAt;
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/fraud/src/main/java/com/amigoscode/fraud/FraudCheckHistoryRepository.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.fraud;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | public interface FraudCheckHistoryRepository
6 | extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/fraud/src/main/java/com/amigoscode/fraud/FraudCheckService.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.fraud;
2 |
3 | import lombok.AllArgsConstructor;
4 | import org.springframework.stereotype.Service;
5 |
6 | import java.time.LocalDateTime;
7 |
8 | @Service
9 | @AllArgsConstructor
10 | public class FraudCheckService {
11 |
12 | private final FraudCheckHistoryRepository fraudCheckHistoryRepository;
13 |
14 | public boolean isFraudulentCustomer(Integer customerId) {
15 | fraudCheckHistoryRepository.save(
16 | FraudCheckHistory.builder()
17 | .customerId(customerId)
18 | .isFraudster(false)
19 | .createdAt(LocalDateTime.now())
20 | .build()
21 | );
22 | return false;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/fraud/src/main/java/com/amigoscode/fraud/FraudController.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.fraud;
2 |
3 | import com.amigoscode.clients.fraud.FraudCheckResponse;
4 | import lombok.AllArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.web.bind.annotation.*;
7 |
8 | @RestController
9 | @RequestMapping("api/v1/fraud-check")
10 | @AllArgsConstructor
11 | @Slf4j
12 | public class FraudController {
13 |
14 | private final FraudCheckService fraudCheckService;
15 |
16 | @GetMapping(path = "{customerId}")
17 | public FraudCheckResponse isFraudster(
18 | @PathVariable("customerId") Integer customerId) {
19 | boolean isFraudulentCustomer = fraudCheckService.
20 | isFraudulentCustomer(customerId);
21 | log.info("fraud check request for customer {}", customerId);
22 |
23 | return new FraudCheckResponse(isFraudulentCustomer);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/fraud/src/main/resources/application-docker.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
3 | spring:
4 | application:
5 | name: fraud
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://postgres:5432/fraud
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://zipkin:9411
20 |
21 | eureka:
22 | client:
23 | service-url:
24 | defaultZone: http://eureka-server:8761/eureka
25 | fetch-registry: true
26 | register-with-eureka: true
27 | enabled: false
--------------------------------------------------------------------------------
/fraud/src/main/resources/application-kube.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
3 | spring:
4 | application:
5 | name: fraud
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://postgres:5432/fraud
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://zipkin:9411
20 |
21 | eureka:
22 | client:
23 | service-url:
24 | defaultZone: http://eureka-server:8761/eureka
25 | fetch-registry: true
26 | register-with-eureka: true
27 | enabled: false
--------------------------------------------------------------------------------
/fraud/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
3 | spring:
4 | application:
5 | name: fraud
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://localhost:5432/fraud
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://localhost:9411
20 | profiles:
21 | active: default
22 |
23 | eureka:
24 | client:
25 | service-url:
26 | defaultZone: http://localhost:8761/eureka
27 | fetch-registry: true
28 | register-with-eureka: true
29 | enabled: true
--------------------------------------------------------------------------------
/fraud/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ,------. ,--.
2 | | .---' ,--.--. ,--,--. ,--.,--. ,-| |
3 | | `--, | .--' ' ,-. | | || | ' .-. |
4 | | |` | | \ '-' | ' '' ' \ `-' |
5 | `--' `--' `--`--' `----' `---'
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/postgres/configmap.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: postgres-config
5 | data:
6 | POSTGRES_DB: amigoscode
7 | POSTGRES_USER: amigoscode
8 | POSTGRES_PASSWORD: password
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/postgres/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: postgres
5 | spec:
6 | selector:
7 | app: postgres
8 | ports:
9 | - port: 5432
10 | targetPort: 5432
11 | type: ClusterIP
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/postgres/statefulset.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: StatefulSet
3 | metadata:
4 | name: postgres
5 | labels:
6 | app: postgres
7 | spec:
8 | serviceName: postgres
9 | replicas: 1
10 | template:
11 | metadata:
12 | name: postgres
13 | labels:
14 | app: postgres
15 | spec:
16 | volumes:
17 | - name: postgres
18 | persistentVolumeClaim:
19 | claimName: postgres-pc-volume-claim
20 | containers:
21 | - name: postgres
22 | image: postgres
23 | imagePullPolicy: IfNotPresent
24 | volumeMounts:
25 | - mountPath: "/var/lib/postgresql/data"
26 | name: postgres
27 | envFrom:
28 | - configMapRef:
29 | name: postgres-config
30 | resources:
31 | requests:
32 | cpu: 100m
33 | memory: 256Mi
34 | limits:
35 | cpu: 500m
36 | memory: 512Mi
37 | restartPolicy: Always
38 | selector:
39 | matchLabels:
40 | app: postgres
41 |
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/postgres/volume.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolume
3 | metadata:
4 | name: postgres-pc-volume
5 | labels:
6 | type: local
7 | app: postgres
8 | spec:
9 | storageClassName: manual
10 | capacity:
11 | storage: 5Gi
12 | accessModes:
13 | - ReadWriteMany
14 | hostPath:
15 | path: /mnt/data
16 | ---
17 | apiVersion: v1
18 | kind: PersistentVolumeClaim
19 | metadata:
20 | name: postgres-pc-volume-claim
21 | labels:
22 | app: postgres
23 | spec:
24 | storageClassName: manual
25 | accessModes:
26 | - ReadWriteMany
27 | resources:
28 | requests:
29 | storage: 5Gi
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/rabbitmq/README.md:
--------------------------------------------------------------------------------
1 | # Deploy RabbitMQ on Kubernetes with the Kubernetes Peer Discovery Plugin to Minikube
2 |
3 | This is an **example** that demonstrates a RabbitMQ deployment on Kubernetes with peer discovery
4 | via `rabbitmq-peer-discovery-k8s` plugin.
5 |
6 | ## Production (Non-)Suitability
7 |
8 | Some values in this example **may or may not be optimal for your deployment**. We encourage users
9 | to get familiar with the [RabbitMQ Peer Discovery guide](https://www.rabbitmq.com/cluster-formation.html), [RabbitMQ Production Checklist](https://www.rabbitmq.com/production-checklist.html)
10 | and the rest of [RabbitMQ documentation](https://www.rabbitmq.com/documentation.html) before going into production.
11 |
12 | Having [metrics](https://www.rabbitmq.com/monitoring.html), both of RabbitMQ and applications that use it,
13 | is critically important when making informed decisions about production systems.
14 |
15 |
16 | ## Pre-requisites
17 |
18 | The example uses, targets or assumes:
19 |
20 | * [Minikube](https://kubernetes.io/docs/setup/learning-environment/minikube/) with the [VirtualBox](https://www.virtualbox.org/) driver (other drivers can be used, too)
21 | * Kubernetes 1.6
22 | * RabbitMQ [Docker image](https://hub.docker.com/_/rabbitmq/) (maintained [by Docker, Inc](https://hub.docker.com/_/rabbitmq/))
23 | * A [StatefulSets controller](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
24 |
25 |
26 | ## Quick Start with Make
27 |
28 | This example comes with a Make target that sets up VirtualBox, Minikube and an example cluster
29 | in a single command. It can be found under this directory. [Homebrew](https://brew.sh/) will be used to install
30 | packages and on macOS, VirtualBox [will need OS permissions to install its kernel module](https://developer.apple.com/library/archive/technotes/tn2459/_index.html).
31 |
32 | The Homebrew cask installer will ask for your password at some point with a prompt that looks like this:
33 |
34 | ```
35 | Changing ownership of paths required by virtualbox; your password may be necessary
36 | ```
37 |
38 | Please inspect the Make file to be extra sure that you understand and agree to what it does.
39 | After enabling 3rd party kernel extensions in OS setings, run the default Make target in this directory:
40 |
41 | ```
42 | make
43 | ```
44 |
45 | which is equivalent to first running
46 |
47 | ```
48 | make start-minikube
49 | ```
50 |
51 | to install VirtualBox and Minikube using Homebrew, then
52 |
53 | ```
54 | make run-in-minikube
55 | ```
56 |
57 | to start Minikube and `kubectl apply` the example, and finally
58 |
59 | ```
60 | make wait-for-rabbitmq
61 | ```
62 |
63 | to wait for cluster formation.
64 |
65 | Once the changes are applied, follow the steps in the Check Cluster Status section below.
66 |
67 | In case you would prefer to install and run Minikube manually, see the following few sections.
68 |
69 |
70 | ## Running the Example Manually with Minikube
71 |
72 | ### Preresuites
73 |
74 | * Make sure that VirtualBox is installed
75 | * Install [`minikube`](https://kubernetes.io/docs/tasks/tools/install-minikube/) and start it with `--vm-driver=virtualbox`
76 | * Install [`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
77 |
78 | ### Start Minikube
79 |
80 | Start a `minikube` virtual machine:
81 |
82 | ``` sh
83 | minikube start --cpus=2 --memory=2040 --disk-size "10 GB" --vm-driver=virtualbox
84 | ```
85 |
86 | ### Create a Namespace
87 |
88 | Create a Kubernetes namespace for RabbitMQ tests:
89 |
90 | ``` sh
91 | kubectl create namespace test-rabbitmq
92 | ```
93 |
94 | ### Set Up Kubernetes Permissions
95 |
96 | In Kubernetes 1.6 or above, RBAC authorization is enabled by default.
97 | This example configures RBAC related bits so that the peer discovery plugin is allowed to access
98 | the nodes information it needs. The `ServiceAccount` and `Role` resources will be created
99 | in the following step.
100 |
101 | ### kubectl Apply Things
102 |
103 | Deploy the config map, services, a stateful set and so on:
104 |
105 | ``` sh
106 | # will apply all files under this directory
107 | kubectl create -f minikube
108 | ```
109 |
110 | ### Check Cluster Status
111 |
112 | Wait for a a few minutes for pods to start. Since this example uses a stateful set with ordered
113 | startup, the pods will be started one by one. To monitor pod startup process, use
114 |
115 | ``` sh
116 | kubectl --namespace="test-rabbitmq" get pods
117 | ```
118 |
119 | To run `rabbitmq-diagnostics cluster_status`:
120 |
121 | ``` sh
122 | FIRST_POD=$(kubectl get pods --namespace test-rabbitmq -l 'app=rabbitmq' -o jsonpath='{.items[0].metadata.name }')
123 | kubectl exec --namespace=test-rabbitmq $FIRST_POD -- rabbitmq-diagnostics cluster_status
124 | ```
125 |
126 | to check cluster status. Note that nodes can take some time to start and discover each other.
127 |
128 | The output should look something like this:
129 |
130 | ```
131 | Cluster status of node rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local ...
132 | Basics
133 |
134 | Cluster name: rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local
135 |
136 | Disk Nodes
137 |
138 | rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local
139 | rabbit@rabbitmq-1.rabbitmq.test-rabbitmq.svc.cluster.local
140 | rabbit@rabbitmq-2.rabbitmq.test-rabbitmq.svc.cluster.local
141 |
142 | Running Nodes
143 |
144 | rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local
145 | rabbit@rabbitmq-1.rabbitmq.test-rabbitmq.svc.cluster.local
146 | rabbit@rabbitmq-2.rabbitmq.test-rabbitmq.svc.cluster.local
147 |
148 | Versions
149 |
150 | rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local: RabbitMQ 3.8.1 on Erlang 22.1.8
151 | rabbit@rabbitmq-1.rabbitmq.test-rabbitmq.svc.cluster.local: RabbitMQ 3.8.1 on Erlang 22.1.8
152 | rabbit@rabbitmq-2.rabbitmq.test-rabbitmq.svc.cluster.local: RabbitMQ 3.8.1 on Erlang 22.1.8
153 |
154 | Alarms
155 |
156 | (none)
157 |
158 | Network Partitions
159 |
160 | (none)
161 |
162 | Listeners
163 |
164 | Node: rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
165 | Node: rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
166 | Node: rabbit@rabbitmq-0.rabbitmq.test-rabbitmq.svc.cluster.local, interface: [::], port: 15672, protocol: http, purpose: HTTP API
167 | Node: rabbit@rabbitmq-1.rabbitmq.test-rabbitmq.svc.cluster.local, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
168 | Node: rabbit@rabbitmq-1.rabbitmq.test-rabbitmq.svc.cluster.local, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
169 | Node: rabbit@rabbitmq-1.rabbitmq.test-rabbitmq.svc.cluster.local, interface: [::], port: 15672, protocol: http, purpose: HTTP API
170 |
171 | Feature flags
172 |
173 | Flag: drop_unroutable_metric, state: enabled
174 | Flag: empty_basic_get_metric, state: enabled
175 | Flag: implicit_default_bindings, state: enabled
176 | Flag: quorum_queue, state: enabled
177 | Flag: virtual_host_metadata, state: enabled
178 | ```
179 |
180 | ### Use Public Minikube IP Address to Connect
181 |
182 | Get the public `minikube` VM IP address:
183 |
184 | ``` sh
185 | minikube ip
186 | # => 192.168.99.104
187 | ```
188 |
189 | The [ports used](https://www.rabbitmq.com/networking.html#ports) by this example are:
190 |
191 | * `amqp://guest:guest@{minikube_ip}:30672`: [AMQP 0-9-1 and AMQP 1.0](https://www.rabbitmq.com/networking.html#ports) client connections
192 | * `http://{minikube_ip}:31672`: [HTTP API and management UI](https://www.rabbitmq.com/management.html)
193 |
194 |
195 | ### Scaling the Number of RabbitMQ Cluster Nodes (Kubernetes Pod Replicas)
196 |
197 | ``` sh
198 | # Odd numbers of nodes are necessary for a clear quorum: 3, 5, 7 and so on
199 | kubectl scale statefulset/rabbitmq --namespace=test-rabbitmq --replicas=5
200 | ```
201 |
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/rabbitmq/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: rabbitmq-config
5 | data:
6 | enabled_plugins: |
7 | [rabbitmq_management,rabbitmq_peer_discovery_k8s].
8 |
9 | rabbitmq.conf: |
10 | ## Cluster formation. See https://www.rabbitmq.com/cluster-formation.html to learn more.
11 | cluster_formation.peer_discovery_backend = rabbit_peer_discovery_k8s
12 | cluster_formation.k8s.host = kubernetes.default.svc.cluster.local
13 | ## Should RabbitMQ node name be computed from the pod's hostname or IP address?
14 | ## IP addresses are not stable, so using [stable] hostnames is recommended when possible.
15 | ## Set to "hostname" to use pod hostnames.
16 | ## When this value is changed, so should the variable used to set the RABBITMQ_NODENAME
17 | ## environment variable.
18 | cluster_formation.k8s.address_type = hostname
19 | ## How often should node cleanup checks run?
20 | cluster_formation.node_cleanup.interval = 30
21 | ## Set to false if automatic removal of unknown/absent nodes
22 | ## is desired. This can be dangerous, see
23 | ## * https://www.rabbitmq.com/cluster-formation.html#node-health-checks-and-cleanup
24 | ## * https://groups.google.com/forum/#!msg/rabbitmq-users/wuOfzEywHXo/k8z_HWIkBgAJ
25 | cluster_formation.node_cleanup.only_log_warning = true
26 | cluster_partition_handling = autoheal
27 | ## See https://www.rabbitmq.com/ha.html#master-migration-data-locality
28 | queue_master_locator=min-masters
29 | ## This is just an example.
30 | ## This enables remote access for the default user with well known credentials.
31 | ## Consider deleting the default user and creating a separate user with a set of generated
32 | ## credentials instead.
33 | ## Learn more at https://www.rabbitmq.com/access-control.html#loopback-users
34 | loopback_users.guest = false
35 |
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/rabbitmq/rbac.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: rabbitmq
6 | ---
7 | kind: Role
8 | apiVersion: rbac.authorization.k8s.io/v1
9 | metadata:
10 | name: rabbitmq-peer-discovery-rbac
11 | rules:
12 | - apiGroups: [""]
13 | resources: ["endpoints"]
14 | verbs: ["get"]
15 | - apiGroups: [""]
16 | resources: ["events"]
17 | verbs: ["create"]
18 | ---
19 | kind: RoleBinding
20 | apiVersion: rbac.authorization.k8s.io/v1
21 | metadata:
22 | name: rabbitmq-peer-discovery-rbac
23 | subjects:
24 | - kind: ServiceAccount
25 | name: rabbitmq
26 | roleRef:
27 | apiGroup: rbac.authorization.k8s.io
28 | kind: Role
29 | name: rabbitmq-peer-discovery-rbac
30 |
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/rabbitmq/services.yaml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: rabbitmq
5 | labels:
6 | app: rabbitmq
7 | type: LoadBalancer
8 | spec:
9 | type: NodePort
10 | ports:
11 | - name: http
12 | protocol: TCP
13 | port: 15672
14 | targetPort: 15672
15 | nodePort: 31672
16 | - name: amqp
17 | protocol: TCP
18 | port: 5672
19 | targetPort: 5672
20 | nodePort: 30672
21 | selector:
22 | app: rabbitmq
23 |
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/rabbitmq/statefulset.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | # See the Prerequisites section of https://www.rabbitmq.com/cluster-formation.html#peer-discovery-k8s.
3 | kind: StatefulSet
4 | metadata:
5 | name: rabbitmq
6 | spec:
7 | serviceName: rabbitmq
8 | # Three nodes is the recommended minimum. Some features may require a majority of nodes
9 | # to be available.
10 | replicas: 1
11 | selector:
12 | matchLabels:
13 | app: rabbitmq
14 | template:
15 | metadata:
16 | labels:
17 | app: rabbitmq
18 | spec:
19 | serviceAccountName: rabbitmq
20 | terminationGracePeriodSeconds: 10
21 | nodeSelector:
22 | # Use Linux nodes in a mixed OS kubernetes cluster.
23 | # Learn more at https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-os
24 | kubernetes.io/os: linux
25 | containers:
26 | - name: rabbitmq-k8s
27 | image: rabbitmq:3.8
28 | volumeMounts:
29 | - name: config-volume
30 | mountPath: /etc/rabbitmq
31 | # Learn more about what ports various protocols use
32 | # at https://www.rabbitmq.com/networking.html#ports
33 | ports:
34 | - name: http
35 | protocol: TCP
36 | containerPort: 15672
37 | - name: amqp
38 | protocol: TCP
39 | containerPort: 5672
40 | livenessProbe:
41 | exec:
42 | # This is just an example. There is no "one true health check" but rather
43 | # several rabbitmq-diagnostics commands that can be combined to form increasingly comprehensive
44 | # and intrusive health checks.
45 | # Learn more at https://www.rabbitmq.com/monitoring.html#health-checks.
46 | #
47 | # Stage 2 check:
48 | command: ["rabbitmq-diagnostics", "status"]
49 | initialDelaySeconds: 60
50 | # See https://www.rabbitmq.com/monitoring.html for monitoring frequency recommendations.
51 | periodSeconds: 60
52 | timeoutSeconds: 15
53 | readinessProbe:
54 | exec:
55 | # This is just an example. There is no "one true health check" but rather
56 | # several rabbitmq-diagnostics commands that can be combined to form increasingly comprehensive
57 | # and intrusive health checks.
58 | # Learn more at https://www.rabbitmq.com/monitoring.html#health-checks.
59 | #
60 | # Stage 1 check:
61 | command: ["rabbitmq-diagnostics", "ping"]
62 | initialDelaySeconds: 20
63 | periodSeconds: 60
64 | timeoutSeconds: 10
65 | imagePullPolicy: Always
66 | env:
67 | - name: MY_POD_NAME
68 | valueFrom:
69 | fieldRef:
70 | apiVersion: v1
71 | fieldPath: metadata.name
72 | - name: MY_POD_NAMESPACE
73 | valueFrom:
74 | fieldRef:
75 | fieldPath: metadata.namespace
76 | - name: RABBITMQ_USE_LONGNAME
77 | value: "true"
78 | # See a note on cluster_formation.k8s.address_type in the config file section
79 | - name: K8S_SERVICE_NAME
80 | value: rabbitmq
81 | - name: RABBITMQ_NODENAME
82 | value: rabbit@$(MY_POD_NAME).$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local
83 | - name: K8S_HOSTNAME_SUFFIX
84 | value: .$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.cluster.local
85 | - name: RABBITMQ_ERLANG_COOKIE
86 | value: "mycookie"
87 | volumes:
88 | - name: config-volume
89 | configMap:
90 | name: rabbitmq-config
91 | items:
92 | - key: rabbitmq.conf
93 | path: rabbitmq.conf
94 | - key: enabled_plugins
95 | path: enabled_plugins
96 |
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/zipkin/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: zipkin
5 | spec:
6 | selector:
7 | app: zipkin
8 | ports:
9 | - port: 9411
10 | targetPort: 9411
11 | protocol: TCP
12 | type: LoadBalancer
--------------------------------------------------------------------------------
/k8s/minikube/bootstrap/zipkin/statefulset.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: StatefulSet
3 | metadata:
4 | name: zipkin
5 | labels:
6 | app: zipkin
7 | spec:
8 | serviceName: zipkin
9 | replicas: 1
10 | template:
11 | metadata:
12 | name: zipkin
13 | labels:
14 | app: zipkin
15 | spec:
16 | containers:
17 | - name: zipkin
18 | image: openzipkin/zipkin
19 | imagePullPolicy: Always
20 | ports:
21 | - containerPort: 9411
22 | protocol: TCP
23 | resources:
24 | requests:
25 | cpu: 100m
26 | memory: 256Mi
27 | limits:
28 | cpu: 200m
29 | memory: 256Mi
30 |
31 | restartPolicy: Always
32 | selector:
33 | matchLabels:
34 | app: zipkin
35 |
--------------------------------------------------------------------------------
/k8s/minikube/services/customer/deployment.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: customer
5 | labels:
6 | app: customer
7 | spec:
8 | replicas: 1
9 | template:
10 | metadata:
11 | name: customer
12 | labels:
13 | app: customer
14 | spec:
15 | containers:
16 | - name: customer
17 | image: amigoscode/customer:latest
18 | imagePullPolicy: Always
19 | ports:
20 | - containerPort: 8080
21 | env:
22 | - name: SPRING_PROFILES_ACTIVE
23 | value: kube
24 | restartPolicy: Always
25 | selector:
26 | matchLabels:
27 | app: customer
28 |
--------------------------------------------------------------------------------
/k8s/minikube/services/customer/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: customer
5 | spec:
6 | selector:
7 | app: customer
8 | ports:
9 | - port: 80
10 | targetPort: 8080
11 | type: LoadBalancer
--------------------------------------------------------------------------------
/k8s/minikube/services/fraud/deployment.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: fraud
5 | labels:
6 | app: fraud
7 | spec:
8 | replicas: 1
9 | template:
10 | metadata:
11 | name: fraud
12 | labels:
13 | app: fraud
14 | spec:
15 | containers:
16 | - name: fraud
17 | image: amigoscode/fraud:latest
18 | imagePullPolicy: Always
19 | ports:
20 | - containerPort: 8081
21 | env:
22 | - name: SPRING_PROFILES_ACTIVE
23 | value: kube
24 | restartPolicy: Always
25 | selector:
26 | matchLabels:
27 | app: fraud
28 |
--------------------------------------------------------------------------------
/k8s/minikube/services/fraud/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: fraud
5 | spec:
6 | selector:
7 | app: fraud
8 | ports:
9 | - port: 80
10 | targetPort: 8081
11 | type: NodePort
--------------------------------------------------------------------------------
/k8s/minikube/services/notification/deployment.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: notification
5 | labels:
6 | app: notification
7 | spec:
8 | replicas: 1
9 | template:
10 | metadata:
11 | name: notification
12 | labels:
13 | app: notification
14 | spec:
15 | containers:
16 | - name: notification
17 | image: amigoscode/notification:latest
18 | imagePullPolicy: Always
19 | ports:
20 | - containerPort: 8083
21 | env:
22 | - name: SPRING_PROFILES_ACTIVE
23 | value: kube
24 | restartPolicy: Always
25 | selector:
26 | matchLabels:
27 | app: notification
28 |
--------------------------------------------------------------------------------
/k8s/minikube/services/notification/service.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: notification
5 | spec:
6 | selector:
7 | app: notification
8 | ports:
9 | - port: 80
10 | targetPort: 8082
11 | type: NodePort
--------------------------------------------------------------------------------
/notification/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | amigosservices
7 | com.amigoscode
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | notification
13 |
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-maven-plugin
19 |
20 |
21 |
22 |
23 |
24 |
25 | build-docker-image
26 |
27 |
28 |
29 | com.google.cloud.tools
30 | jib-maven-plugin
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-data-jpa
45 |
46 |
47 | org.postgresql
48 | postgresql
49 | runtime
50 |
51 |
52 | org.springframework.cloud
53 | spring-cloud-starter-netflix-eureka-client
54 |
55 |
56 | org.springframework.cloud
57 | spring-cloud-starter-sleuth
58 |
59 |
60 | org.springframework.cloud
61 | spring-cloud-sleuth-zipkin
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-amqp
66 |
67 |
68 | com.amigoscode
69 | amqp
70 | 1.0-SNAPSHOT
71 | compile
72 |
73 |
74 | com.amigoscode
75 | clients
76 | 1.0-SNAPSHOT
77 | compile
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/Notification.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 | import lombok.Setter;
8 | import lombok.ToString;
9 |
10 | import javax.persistence.*;
11 | import java.time.LocalDateTime;
12 |
13 | @Entity
14 | @Builder
15 | @AllArgsConstructor
16 | @NoArgsConstructor
17 | @Getter
18 | @Setter
19 | @ToString
20 | public class Notification {
21 |
22 | @Id
23 | @SequenceGenerator(
24 | name = "notification_id_sequence",
25 | sequenceName = "notification_id_sequence"
26 | )
27 | @GeneratedValue(
28 | strategy = GenerationType.SEQUENCE,
29 | generator = "notification_id_sequence"
30 | )
31 | private Integer notificationId;
32 | private Integer toCustomerId;
33 | private String toCustomerEmail;
34 | private String sender;
35 | private String message;
36 | private LocalDateTime sentAt;
37 | }
38 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/NotificationApplication.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification;
2 |
3 | import com.amigoscode.amqp.RabbitMQMessageProducer;
4 | import org.springframework.boot.CommandLineRunner;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.PropertySource;
9 | import org.springframework.context.annotation.PropertySources;
10 |
11 | @SpringBootApplication(
12 | scanBasePackages = {
13 | "com.amigoscode.notification",
14 | "com.amigoscode.amqp",
15 | }
16 | )
17 | @PropertySources({
18 | @PropertySource("classpath:clients-${spring.profiles.active}.properties")
19 | })
20 | public class NotificationApplication {
21 | public static void main(String[] args) {
22 | SpringApplication.run(NotificationApplication.class, args);
23 | }
24 |
25 | // @Bean
26 | // CommandLineRunner commandLineRunner(
27 | // RabbitMQMessageProducer producer,
28 | // NotificationConfig notificationConfig
29 | // ) {
30 | // return args -> {
31 | // producer.publish(
32 | // new Person("Ali", 18),
33 | // notificationConfig.getInternalExchange(),
34 | // notificationConfig.getInternalNotificationRoutingKey());
35 | // };
36 | // }
37 | //
38 | // record Person(String name, int age){}
39 | }
40 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/NotificationConfig.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification;
2 |
3 | import org.springframework.amqp.core.Binding;
4 | import org.springframework.amqp.core.BindingBuilder;
5 | import org.springframework.amqp.core.Queue;
6 | import org.springframework.amqp.core.TopicExchange;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | @Configuration
12 | public class NotificationConfig {
13 |
14 | @Value("${rabbitmq.exchanges.internal}")
15 | private String internalExchange;
16 |
17 | @Value("${rabbitmq.queues.notification}")
18 | private String notificationQueue;
19 |
20 | @Value("${rabbitmq.routing-keys.internal-notification}")
21 | private String internalNotificationRoutingKey;
22 |
23 | @Bean
24 | public TopicExchange internalTopicExchange() {
25 | return new TopicExchange(this.internalExchange);
26 | }
27 |
28 | @Bean
29 | public Queue notificationQueue() {
30 | return new Queue(this.notificationQueue);
31 | }
32 |
33 | @Bean
34 | public Binding internalToNotificationBinding() {
35 | return BindingBuilder
36 | .bind(notificationQueue())
37 | .to(internalTopicExchange())
38 | .with(this.internalNotificationRoutingKey);
39 | }
40 |
41 |
42 | public String getInternalExchange() {
43 | return internalExchange;
44 | }
45 |
46 | public String getNotificationQueue() {
47 | return notificationQueue;
48 | }
49 |
50 | public String getInternalNotificationRoutingKey() {
51 | return internalNotificationRoutingKey;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/NotificationController.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification;
2 |
3 | import com.amigoscode.clients.notification.NotificationRequest;
4 | import lombok.AllArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.web.bind.annotation.PostMapping;
7 | import org.springframework.web.bind.annotation.RequestBody;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("api/v1/notification")
13 | @AllArgsConstructor
14 | @Slf4j
15 | public class NotificationController {
16 |
17 | private final NotificationService notificationService;
18 |
19 | @PostMapping
20 | public void sendNotification(@RequestBody NotificationRequest notificationRequest) {
21 | log.info("New notification... {}", notificationRequest);
22 | notificationService.send(notificationRequest);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/NotificationRepository.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | public interface NotificationRepository extends JpaRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/NotificationService.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification;
2 |
3 | import com.amigoscode.clients.notification.NotificationRequest;
4 | import lombok.AllArgsConstructor;
5 | import org.springframework.stereotype.Service;
6 |
7 | import java.time.LocalDateTime;
8 |
9 | @Service
10 | @AllArgsConstructor
11 | public class NotificationService {
12 |
13 | private final NotificationRepository notificationRepository;
14 |
15 | public void send(NotificationRequest notificationRequest) {
16 | notificationRepository.save(
17 | Notification.builder()
18 | .toCustomerId(notificationRequest.toCustomerId())
19 | .toCustomerEmail(notificationRequest.toCustomerName())
20 | .sender("Amigoscode")
21 | .message(notificationRequest.message())
22 | .sentAt(LocalDateTime.now())
23 | .build()
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/notification/src/main/java/com/amigoscode/notification/rabbitmq/NotificationConsumer.java:
--------------------------------------------------------------------------------
1 | package com.amigoscode.notification.rabbitmq;
2 |
3 | import com.amigoscode.clients.notification.NotificationRequest;
4 | import com.amigoscode.notification.NotificationService;
5 | import lombok.AllArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
8 | import org.springframework.stereotype.Component;
9 |
10 | @Component
11 | @AllArgsConstructor
12 | @Slf4j
13 | public class NotificationConsumer {
14 |
15 | private final NotificationService notificationService;
16 |
17 | @RabbitListener(queues = "${rabbitmq.queues.notification}")
18 | public void consumer(NotificationRequest notificationRequest) {
19 | log.info("Consumed {} from queue", notificationRequest);
20 | notificationService.send(notificationRequest);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/notification/src/main/resources/application-docker.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8082
3 | spring:
4 | application:
5 | name: notification
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://postgres:5432/notification
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://zipkin:9411
20 | rabbitmq:
21 | addresses: rabbitmq:5672
22 | eureka:
23 | client:
24 | service-url:
25 | defaultZone: http://eureka-server:8761/eureka
26 | fetch-registry: true
27 | register-with-eureka: true
28 | enabled: false
29 |
30 | rabbitmq:
31 | exchanges:
32 | internal: internal.exchange
33 | queues:
34 | notification: notification.queue
35 | routing-keys:
36 | internal-notification: internal.notification.routing-key
37 |
38 |
--------------------------------------------------------------------------------
/notification/src/main/resources/application-kube.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8082
3 | spring:
4 | application:
5 | name: notification
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://postgres:5432/notification
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://zipkin:9411
20 | rabbitmq:
21 | addresses: rabbitmq:5672
22 | eureka:
23 | client:
24 | service-url:
25 | defaultZone: http://eureka-server:8761/eureka
26 | fetch-registry: true
27 | register-with-eureka: true
28 | enabled: false
29 |
30 | rabbitmq:
31 | exchanges:
32 | internal: internal.exchange
33 | queues:
34 | notification: notification.queue
35 | routing-keys:
36 | internal-notification: internal.notification.routing-key
37 |
38 |
--------------------------------------------------------------------------------
/notification/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8082
3 | spring:
4 | application:
5 | name: notification
6 | datasource:
7 | password: password
8 | url: jdbc:postgresql://localhost:5432/notification
9 | username: amigoscode
10 | jpa:
11 | hibernate:
12 | ddl-auto: create-drop
13 | properties:
14 | hibernate:
15 | dialect: org.hibernate.dialect.PostgreSQLDialect
16 | format_sql: true
17 | show-sql: true
18 | zipkin:
19 | base-url: http://localhost:9411
20 | rabbitmq:
21 | addresses: localhost:5672
22 | profiles:
23 | active: default
24 | eureka:
25 | client:
26 | service-url:
27 | defaultZone: http://localhost:8761/eureka
28 | fetch-registry: true
29 | register-with-eureka: true
30 | enabled: true
31 |
32 | rabbitmq:
33 | exchanges:
34 | internal: internal.exchange
35 | queues:
36 | notification: notification.queue
37 | routing-keys:
38 | internal-notification: internal.notification.routing-key
39 |
40 |
--------------------------------------------------------------------------------
/notification/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ,--. ,--. ,--. ,--. ,---. ,--. ,--. ,--.
2 | | ,'.| | ,---. ,-' '-. `--' / .-' `--' ,---. ,--,--. ,-' '-. `--' ,---. ,--,--,
3 | | |' ' | | .-. | '-. .-' ,--. | `-, ,--. | .--' ' ,-. | '-. .-' ,--. | .-. | | \
4 | | | ` | ' '-' ' | | | | | .-' | | \ `--. \ '-' | | | | | ' '-' ' | || |
5 | `--' `--' `---' `--' `--' `--' `--' `---' `--`--' `--' `--' `---' `--''--'
6 |
7 | ${application.title} ${application.version}
8 | Powered by Spring Boot ${spring-boot.version}
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | com.amigoscode
8 | amigosservices
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 |
13 | customer
14 | fraud
15 | eureka-server
16 | clients
17 | notification
18 | apigw
19 | amqp
20 |
21 |
22 | amigosservices
23 | https://www.amigoscode.com
24 |
25 |
26 | UTF-8
27 | 17
28 | 17
29 | 2.5.7
30 | 2.5.7
31 | 2020.0.3
32 | amigoscode/${project.artifactId}:${project.version}
33 |
34 |
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-dependencies
40 | ${spring.boot.dependencies.version}
41 | import
42 | pom
43 |
44 |
45 | org.springframework.cloud
46 | spring-cloud-dependencies
47 | ${spring.cloud-version}
48 | pom
49 | import
50 |
51 |
52 |
53 |
54 |
55 |
56 | org.projectlombok
57 | lombok
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-starter-test
62 |
63 |
64 | org.springframework.cloud
65 | spring-cloud-starter-openfeign
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-maven-plugin
75 | ${spring.boot.maven.plugin.version}
76 |
77 |
78 |
79 | repackage
80 |
81 |
82 |
83 |
84 |
85 | com.google.cloud.tools
86 | jib-maven-plugin
87 | 3.1.4
88 |
89 |
90 | eclipse-temurin:17@sha256:2b47a8ea946ce1e5365a1562414ed576e378b7b670cadff3fb98ebecf2890cdc
91 |
92 |
93 | arm64
94 | linux
95 |
96 |
97 | amd64
98 | linux
99 |
100 |
101 |
102 |
103 |
104 | latest
105 |
106 |
107 |
108 |
109 |
110 | package
111 |
112 | build
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | org.apache.maven.plugins
122 | maven-compiler-plugin
123 | 3.8.0
124 |
125 | 17
126 | 17
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------