Skip to content

Latest commit

 

History

History
172 lines (143 loc) · 5.8 KB

File metadata and controls

172 lines (143 loc) · 5.8 KB

Lab 12: Asynchronous Communication with RabbitMQ

Objective

Implement asynchronous communication between UserService, ProductService, and OrderService using RabbitMQ. This setup will allow microservices to exchange messages efficiently, improving decoupling and scalability.


Steps

1. Set Up RabbitMQ in Docker Compose

  • Open docker-compose.yml in the MicroservicesProject directory.
  • Add the following configuration for RabbitMQ:
    rabbitmq:
      image: rabbitmq:3-management
      ports:
        - "5672:5672"     # RabbitMQ server port
        - "15672:15672"   # Management console port
      environment:
        - RABBITMQ_DEFAULT_USER=guest
        - RABBITMQ_DEFAULT_PASS=guest

2. Add RabbitMQ Dependencies to Each Microservice

  • In each service (UserService, ProductService, and OrderService), open pom.xml.
  • Add the Spring Boot starter for RabbitMQ:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

3. Configure RabbitMQ Properties in Each Microservice

  • In each service’s application.properties, add the RabbitMQ connection details:
    spring.rabbitmq.host=localhost
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=guest
    spring.rabbitmq.password=guest

4. Define a Message Model Class

  • In each service, create a Message class to represent the message structure:
    public class OrderMessage {
        private Long orderId;
        private Long userId;
        private Long productId;
        private int quantity;
    
        // Getters and Setters
    }

5. Set Up a Message Producer in OrderService

  • In OrderService, create a MessageProducer class to publish messages to RabbitMQ:
    @Service
    public class MessageProducer {
    
        private final RabbitTemplate rabbitTemplate;
    
        @Autowired
        public MessageProducer(RabbitTemplate rabbitTemplate) {
            this.rabbitTemplate = rabbitTemplate;
        }
    
        public void sendOrderMessage(OrderMessage orderMessage) {
            rabbitTemplate.convertAndSend("order.exchange", "order.routingKey", orderMessage);
        }
    }

6. Define RabbitMQ Configuration in OrderService

  • In OrderService, create a RabbitMQConfig class to define the exchange, queue, and routing key:
    @Configuration
    public class RabbitMQConfig {
    
        @Bean
        public TopicExchange exchange() {
            return new TopicExchange("order.exchange");
        }
    
        @Bean
        public Queue queue() {
            return new Queue("order.queue");
        }
    
        @Bean
        public Binding binding(Queue queue, TopicExchange exchange) {
            return BindingBuilder.bind(queue).to(exchange).with("order.routingKey");
        }
    }

7. Publish Message in OrderService

  • In the order creation method, publish an order message to RabbitMQ:
    @Autowired
    private MessageProducer messageProducer;
    
    public Order createOrder(Order order) {
        Order savedOrder = orderRepository.save(order);
        OrderMessage orderMessage = new OrderMessage(savedOrder.getId(), savedOrder.getUserId(), savedOrder.getProductId(), savedOrder.getQuantity());
        messageProducer.sendOrderMessage(orderMessage);
        return savedOrder;
    }

8. Set Up a Message Consumer in ProductService

  • In ProductService, create a MessageConsumer class to listen for order messages:
    @Service
    public class MessageConsumer {
    
        @RabbitListener(queues = "order.queue")
        public void receiveOrderMessage(OrderMessage orderMessage) {
            System.out.println("Received order: " + orderMessage);
            // Process the order (e.g., update product stock)
        }
    }

9. Test Asynchronous Communication with RabbitMQ

  • Start all services and RabbitMQ with Docker Compose:
    docker-compose up -d
  • Use Postman to send a request to OrderService to create an order. Verify that the message is sent to ProductService.

10. Verify Messages in RabbitMQ Management Console

  • Access the RabbitMQ management console at http://localhost:15672.
  • Log in with username guest and password guest.
  • Go to the Queues tab to monitor messages in order.queue.

11. Add Error Handling and Retries for Message Processing

  • In MessageConsumer, add error handling logic to retry message processing in case of errors:
    @RabbitListener(queues = "order.queue")
    public void receiveOrderMessage(OrderMessage orderMessage) {
        try {
            // Process message
        } catch (Exception e) {
            System.out.println("Error processing message, will retry.");
            throw e; // Message will be requeued
        }
    }

12. Summary of Lab

  • Review what was covered:
    • Configured RabbitMQ for asynchronous messaging.
    • Set up message producers and consumers for OrderService and ProductService.
    • Verified message flow and monitored RabbitMQ queues.

Extra Exercise (20 minutes)

  1. Implement a New Queue and Message Type:

    • Create a new queue (e.g., user.queue) for UserService to listen for messages related to user actions.
    • Test sending and receiving user-related messages in RabbitMQ.
  2. Implement Delayed Messaging:

    • Configure a delay in message processing for specific message types.
    • Test that messages are processed after a delay and verify the behavior in the RabbitMQ console.
  3. Monitor and Handle Dead Letter Messages:

    • Set up a dead-letter queue for messages that fail to be processed after multiple attempts.
    • Send messages that intentionally cause an error and verify that they are sent to the dead-letter queue.