Microservices — Cheat Sheet
RabbitMQ · 2 topics. Download the PDF or the Instagram carousel and share it.
Cheat Sheet · AiCanCode.org
Microservices
RabbitMQ2 topicsQuick revision reference
1
RabbitMQ in Microservices
RabbitMQ decouples microservices for asynchronous workflows, saga choreography, event notification, and integration events; use separate exchanges per service to avoid coupling.
- ✓Exchange-per-service: each service owns its exchange; consumers bind their own queues.
- ✓Publishing service does not know who consumes — loose coupling by design.
- ✓Saga choreography: services react to each other's events without a central coordinator.
- ✓Compensating transactions must be idempotent — messages may be delivered more than once.
- ✓convertSendAndReceive provides RPC (blocking request-reply) over AMQP via a temporary reply queue.
- ✓Always publish integration events AFTER the DB transaction commits (Transactional Outbox or @TransactionalEventListener).
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());
}
}2
Error Handling Patterns
Combine retry (with back-off), DLX, and poison-message detection to build robust error handling; alert on DLQ growth and build replay tooling for production incidents.
- ✓Retry transient failures in-process (RetryInterceptorBuilder); dead-letter permanent failures for investigation.
- ✓RejectAndDontRequeueRecoverer sends nack + no-requeue after exhausting retries, triggering the DLX routing.
- ✓x-death headers on DLQ messages record the death count, reason (rejected/expired/maxlen), and originating queue.
- ✓Alert on DLQ depth growing — it means messages are failing consistently; investigate before the DLQ fills.
- ✓Poison messages loop forever without a death-count check; quarantine messages that die more than N times.
- ✓Build replay tooling before an incident — being able to re-publish DLQ messages after a bug fix is critical for recovery.
Java — RetryInterceptorBuilder with exponential back-off
@Configuration
public class ErrorHandlingConfig {
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
ConnectionFactory connectionFactory,
RabbitTemplate rabbitTemplate) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setAcknowledgeMode(AcknowledgeMode.AUTO); // nack triggers retry
// After 3 retries → dead-letter the message
factory.setAdviceChain(
RetryInterceptorBuilder.stateless()
.maxAttempts(3)
.backOffOptions(500, 2.0, 8000) // 0.5s, 1s, 2s → DLQ
.recoverer(new RejectAndDontRequeueRecoverer()) // nack + no requeue
.build()
);
return factory;
}
}
@RabbitListener(queues = "orders.queue")
public void processOrder(OrderEvent event) {
// If this throws, Spring AMQP retries up to 3x before dead-lettering
orderService.process(event);
}Learn this free with Aria, your AI tutor → AiCanCode.org/learn/rabbitmq