Home/Learn/RabbitMQ/RabbitMQ in Microservices

RabbitMQ in Microservices

Intermediate
Microservices

RabbitMQ decouples microservices for asynchronous workflows, saga choreography, event notification, and integration events; use separate exchanges per service to avoid coupling.

Overview

In microservices, RabbitMQ acts as the asynchronous communication backbone. Each service owns one exchange (its outbox) and publishes domain events to it. Other services bind their own queues to that exchange to receive events they care about. This ownership model prevents tight coupling — the publishing service does not know who listens. Common patterns: event notification (fire-and-forget), event-carried state transfer (embed full state in the event), saga choreography (services react to each other's events), and request/reply (RPC-over-AMQP for synchronous-like interactions).

Exchange-Per-Service Pattern

Each microservice owns its own exchange. Other services bind queues to consume its events. This is the ownership model that keeps services independent — each service only manages its own exchange.

Java — exchange-per-service ownership model
// order-service owns the "order-service" exchange
@Configuration // in order-service
public class OrderExchangeConfig {
    @Bean
    public TopicExchange orderServiceExchange() {
        return ExchangeBuilder.topicExchange("order-service")
            .durable(true).build();
    }
}

// inventory-service declares its own queue and binds to order-service exchange
@Configuration // in inventory-service
public class InventoryBindings {
    @Bean
    public TopicExchange orderServiceExchange() {
        // Reference the exchange owned by order-service
        return ExchangeBuilder.topicExchange("order-service")
            .durable(true).build();  // idempotent — OK to declare again
    }
    @Bean
    public Queue inventoryOrderQueue() {
        return QueueBuilder.durable("inventory-service.order-placed").build();
    }
    @Bean
    public Binding inventoryOrderBinding(Queue q, TopicExchange ex) {
        return BindingBuilder.bind(q).to(ex).with("order.placed");
    }
    @RabbitListener(queues = "inventory-service.order-placed")
    public void onOrderPlaced(OrderPlacedEvent event) {
        inventoryService.reserve(event.getItems());
    }
}

Saga Choreography with RabbitMQ

Each saga step publishes a success or failure event. The next service listens and reacts. Compensating transactions undo previous steps on failure. No central coordinator — services self-organise through events.

Java — saga choreography with RabbitMQ
// Order placement saga — choreography via RabbitMQ
//
// order-service    →  "order.placed"       → inventory-service
// inventory-service → "inventory.reserved" → billing-service
//                   → "inventory.failed"   → order-service (compensate)
// billing-service  → "payment.charged"    → order-service (confirm)
//                  → "payment.failed"     → order-service + inventory-service (compensate)

// order-service — start saga
@Transactional
public Order placeOrder(PlaceOrderRequest req) {
    Order order = orderRepo.save(new Order(req).withStatus(PENDING));
    rabbitTemplate.convertAndSend("order-service", "order.placed",
        new OrderPlacedEvent(order.getId(), req.getItems(), req.getCustomerId()));
    return order;
}

// order-service — compensate on payment failure
@RabbitListener(queues = "order-service.payment-failed")
public void onPaymentFailed(PaymentFailedEvent event) {
    orderRepo.findById(event.getOrderId()).ifPresent(order -> {
        order.cancel();
        orderRepo.save(order);
        rabbitTemplate.convertAndSend("order-service", "order.cancelled",
            new OrderCancelledEvent(order.getId()));
    });
}

Request-Reply (RPC) Pattern

For synchronous-style requests over AMQP, producers set a reply-to queue name and correlation-id in the message properties. The consumer processes the request and publishes the response to the reply-to queue.

Java — RPC request-reply with RabbitTemplate
// RPC using RabbitTemplate.convertSendAndReceive
@Service
public class PricingClient {
    private final RabbitTemplate rabbitTemplate;

    public PriceResponse getPrice(PriceRequest request) {
        // Blocks until response arrives or timeout
        PriceResponse response = (PriceResponse) rabbitTemplate
            .convertSendAndReceive(
                "pricing-service",   // exchange
                "price.query",       // routing key
                request              // serialised as JSON
            );
        // Under the hood: sets reply-to = anonymous reply queue
        // and correlation-id; waits for reply
        if (response == null) throw new PricingServiceTimeoutException();
        return response;
    }
}

// pricing-service consumer — respond via @SendTo
@RabbitListener(queues = "pricing-service.price-query")
@SendTo  // sends return value to the reply-to address in request headers
public PriceResponse handlePriceQuery(PriceRequest request) {
    return pricingEngine.calculate(request);
}

Key Points to Remember

  • 1Exchange-per-service: each service owns its exchange; consumers bind their own queues.
  • 2Publishing service does not know who consumes — loose coupling by design.
  • 3Saga choreography: services react to each other's events without a central coordinator.
  • 4Compensating transactions must be idempotent — messages may be delivered more than once.
  • 5convertSendAndReceive provides RPC (blocking request-reply) over AMQP via a temporary reply queue.
  • 6Always publish integration events AFTER the DB transaction commits (Transactional Outbox or @TransactionalEventListener).

Interview Questions

Sign in to ask Aria
1

What is the exchange-per-service pattern and why does it reduce coupling?

MediumAmazon
2

How does Saga choreography work with RabbitMQ?

HardNetflix
3

What is the request-reply (RPC) pattern in RabbitMQ and how is it implemented?

MediumPivotal
4

Why must compensating transactions in a saga be idempotent?

HardUber
5

How do you ensure an event is published to RabbitMQ only after a DB transaction commits?

HardLinkedIn

Ask Aria about RabbitMQ in Microservices

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…