├── .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 | ![Screenshot 2021-11-30 at 12 32 51](https://user-images.githubusercontent.com/40702606/144061535-7a42e85b-59d6-4f7f-9c35-18a48b49e6de.png) 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 | --------------------------------------------------------------------------------