Skip to content

Commit

Permalink
Merge pull request #2 from gbzarelli/IMPLEMENT_MESSAGE_QUEUING_#1
Browse files Browse the repository at this point in the history
Implement message queuing #1
  • Loading branch information
gbzarelli authored May 25, 2019
2 parents 4284320 + 512453f commit 9af5cf5
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 10 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
- Consultar uma venda pelo seu identificador;
- Registrar uma nova venda de discos calculando o valor total de cashback considerando a tabela.

O serviço será alimentado pela base de dados do `spotfy` [`web-api`](https://developer.spotify.com/documentation/web-api/quick-start/)
- O serviço será alimentado pela base de dados do `spotfy` [`web-api`](https://developer.spotify.com/documentation/web-api/quick-start/)
- Cada venda poderá ter 1 ou mais discos selecionados, o cashback deverá ser calculado e armazenado individualmente para cada disco bem como o cashback total da venda.

Cada venda poderá ter 1 ou mais discos selecionados, o cashback deverá ser calculado e armazenado individualmente para cada disco bem como o cashback total da venda.
Extra:

- Ao registrar uma venda, a API deve enviar uma mensagem a um serviço de mensageria passando o número único da venda.

## Tecnologias

Expand All @@ -32,6 +35,7 @@
- [`Swagger`](https://swagger.io) - Documentação de API de forma dinâmica
- [`JPA/Hibernate`](https://hibernate.org/orm/) - Framework para persistencia de dados / ORM
- [`Docker`](https://www.docker.com) - Executa e gerencia aplicações dentro de invólucros chamados containers
- [`RabbitMQ`](https://www.rabbitmq.com) - RabbitMQ é um servidor de mensageria
- [`jUnit5 e Mockito`](https://junit.org/junit5/) - Execução de testes

## Executando com Docker em ambiente de desenvolvimento
Expand Down
12 changes: 12 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ version: '3'

services:

rabbitmq:
container_name: rabbit-mq
image: rabbitmq:3-management-alpine
ports:
- "15672:15672"
- "5672:5672"
networks:
- musicstore-network
environment:
RABBITMQ_DEFAULT_USER: rabbitmq
RABBITMQ_DEFAULT_PASS: rabbitmq

mysql:
image: mysql:5.7
container_name: music-store-mysql
Expand Down
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>br.com.beblue</groupId>
<artifactId>music-store-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>1.1.0</version>

<name>Music Store</name>
<description>API for querying and selling discs</description>
Expand Down Expand Up @@ -72,6 +72,10 @@
<version>${spotify.web-api.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class MusicStoreApplication {

Expand Down
33 changes: 33 additions & 0 deletions src/main/java/br/com/beblue/musicstore/amq/SaleAMQSender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package br.com.beblue.musicstore.amq;

import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import static br.com.beblue.musicstore.util.BeanConst.BEAN_SALE_EXCHANGE;
import static br.com.beblue.musicstore.util.ResourceConst.KEY_APPLICATION_MQ_SALE_ROUTING_KEY;

@Component
public class SaleAMQSender {

@Value(KEY_APPLICATION_MQ_SALE_ROUTING_KEY)
private String exchangeRoutingKey;

private final RabbitTemplate rabbitTemplate;
private final TopicExchange topicExchange;

@Autowired
public SaleAMQSender(RabbitTemplate rabbitTemplate, @Qualifier(BEAN_SALE_EXCHANGE) TopicExchange topicExchange) {
this.rabbitTemplate = rabbitTemplate;
this.topicExchange = topicExchange;
}

public void send(String order) throws AmqpException {
rabbitTemplate.convertAndSend(topicExchange.getName(), exchangeRoutingKey, order);
}

}
23 changes: 20 additions & 3 deletions src/main/java/br/com/beblue/musicstore/service/SaleService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package br.com.beblue.musicstore.service;

import br.com.beblue.musicstore.amq.SaleAMQSender;
import br.com.beblue.musicstore.dto.SaleRequestDTO;
import br.com.beblue.musicstore.dto.SaleResponseDTO;
import br.com.beblue.musicstore.exception.NoValuePresentException;
Expand All @@ -9,7 +10,6 @@
import br.com.beblue.musicstore.model.entity.SaleEntity;
import br.com.beblue.musicstore.model.repository.DiscRepository;
import br.com.beblue.musicstore.model.repository.SaleRepository;
import br.com.beblue.musicstore.util.converter.DiscSaleConverter;
import br.com.beblue.musicstore.util.converter.SaleConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand All @@ -22,12 +22,14 @@ public class SaleService {
private final SaleRepository saleRepository;
private final DiscRepository discRepository;
private final CashbackService cashbackService;
private final SaleAMQSender saleAMQSender;

@Autowired
public SaleService(SaleRepository saleRepository, DiscRepository discRepository, CashbackService cashbackService) {
public SaleService(SaleRepository saleRepository, DiscRepository discRepository, CashbackService cashbackService, SaleAMQSender saleAMQSender) {
this.saleRepository = saleRepository;
this.discRepository = discRepository;
this.cashbackService = cashbackService;
this.saleAMQSender = saleAMQSender;
}

public SaleResponseDTO registerOrder(SaleRequestDTO item) throws NoValuePresentException {
Expand All @@ -52,11 +54,26 @@ public SaleResponseDTO registerOrder(SaleRequestDTO item) throws NoValuePresentE
saleEntity.addDiscSaleEntity(discSaleEntity);
});

saleRepository.save(saleEntity);
persist(saleEntity);
notifyMessageQueue(saleEntity);

return SaleConverter.saleEntityToSaleResponseDTO(saleEntity);
}

private void notifyMessageQueue(SaleEntity saleEntity) {
// Caso falte comunicação ou de erro de persistencia, o sistema não
//deve parar. Posteriormente tratar o Log de erro
try {
saleAMQSender.send(saleEntity.getUuid());
} catch (Throwable t) {
t.printStackTrace();
}
}

private void persist(SaleEntity saleEntity) {
saleRepository.save(saleEntity);
}

private double getCashbackPrice(double price, Integer cashback) {
return (price * cashback) / 100;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package br.com.beblue.musicstore.settings.amq;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import static br.com.beblue.musicstore.util.BeanConst.BEAN_SALE_QUEUE;
import static br.com.beblue.musicstore.util.BeanConst.BEAN_SALE_EXCHANGE;
import static br.com.beblue.musicstore.util.ResourceConst.*;

@Configuration
public class SaleConfig {

@Value(KEY_APPLICATION_MQ_SALE_QUEUE_NAME)
private String queueName;

@Value(KEY_APPLICATION_MQ_SALE_EXCHANGE_NAME)
private String exchangeName;

@Value(KEY_APPLICATION_MQ_SALE_ROUTING_KEY)
private String exchangeRoutingKey;

@Bean(BEAN_SALE_QUEUE)
Queue queue() {
return new Queue(queueName, true);
}

@Bean(BEAN_SALE_EXCHANGE)
TopicExchange exchange() {
return new TopicExchange(exchangeName);
}

@Bean
@DependsOn({BEAN_SALE_QUEUE, BEAN_SALE_EXCHANGE})
Binding binding(@Qualifier(BEAN_SALE_QUEUE) Queue queue, @Qualifier(BEAN_SALE_EXCHANGE) TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(exchangeRoutingKey);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import java.io.IOException;
import java.util.Objects;

import static br.com.beblue.musicstore.util.ResourceConst.KEY_SPOTIFY_CLIENT_ID;
import static br.com.beblue.musicstore.util.ResourceConst.KEY_SPOTIFY_CLIENT_SECRET;

@Component
public class SpotifyAPI {

Expand All @@ -18,8 +21,8 @@ public class SpotifyAPI {
private final String clientSecret;
private Credentials credentials;

public SpotifyAPI(@Value("${spotify.client.id}") String clientId,
@Value("${spotify.client.secret}") String clientSecret
public SpotifyAPI(@Value(KEY_SPOTIFY_CLIENT_ID) String clientId,
@Value(KEY_SPOTIFY_CLIENT_SECRET) String clientSecret
) {
this.clientId = clientId;
this.clientSecret = clientSecret;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/br/com/beblue/musicstore/util/BeanConst.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package br.com.beblue.musicstore.util;

public class BeanConst {
public static final String BEAN_SALE_QUEUE = "saleQueue";
public static final String BEAN_SALE_EXCHANGE = "saleExchange";
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
public class ResourceConst {
public static final String ACTIVE_PROFILES_TEST_VALUE = "test";
public static final String KEY_SPOTIFY_CLIENT_ID = "${spotify.client.id}";
public static final String KEY_SPOTIFY_CLIENT_SECRET = "${spotify.client.secret}";
public static final String KEY_APPLICATION_ENV = "${application.environment}";
public static final String KEY_APPLICATION_MQ_SALE_QUEUE_NAME = "${application.mq.sale.queue.name}";
public static final String KEY_APPLICATION_MQ_SALE_EXCHANGE_NAME = "${application.mq.sale.exchange.name}";
public static final String KEY_APPLICATION_MQ_SALE_ROUTING_KEY = "${application.mq.sale.exchange.routing-key}";
}
5 changes: 4 additions & 1 deletion src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ spring:
jpa:
properties:
hibernate:
show_sql: false
show_sql: false

rabbitmq:
host: rabbitmq
15 changes: 14 additions & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ application:
version: @project.version@
environment: default

mq:
sale:
queue:
name: sales
exchange:
name: sales-exchange
routing-key: musicstore.sales

spotify:
client:
id: 1228515c3a654087b2a33907226e09e9
Expand All @@ -33,4 +41,9 @@ spring:
user: ${spring.datasource.username}
password: ${spring.datasource.password}
baseline-on-migrate: true
validate-on-migrate: false
validate-on-migrate: false

rabbitmq:
host: localhost
username: rabbitmq
password: rabbitmq
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package br.com.beblue.musicstore.service;

import br.com.beblue.musicstore.amq.SaleAMQSender;
import br.com.beblue.musicstore.dto.SaleRequestDTO;
import br.com.beblue.musicstore.dto.SaleResponseDTO;
import br.com.beblue.musicstore.exception.NoValuePresentException;
Expand Down Expand Up @@ -41,6 +42,9 @@ class SaleServiceTest {
@MockBean
CashbackService cashbackService;

@MockBean
SaleAMQSender saleAMQSender;

@Test
void test_no_value_present_exception_with_empty_list() {
Assertions.assertThrows(NoValuePresentException.class, () -> {
Expand Down

0 comments on commit 9af5cf5

Please sign in to comment.