Backend Development 13 min read

8 Real-World Scenarios for Using Message Queues in Modern Applications

This article explores eight practical use cases for message queues—including asynchronous processing, service decoupling, traffic shaping, delayed tasks, log collection, distributed transactions, remote calls, and broadcast notifications—providing code examples and architectural guidance for building robust backend systems.

macrozheng
macrozheng
macrozheng
8 Real-World Scenarios for Using Message Queues in Modern Applications

1. Asynchronous Processing

When a user registers, sending a confirmation SMS or email can be time‑consuming and may block the registration API; using a message queue to handle the notification asynchronously prevents the main flow from being delayed.

For example, after successfully saving user information, the system publishes a registration success message to the queue, and a consumer later sends the SMS/email.
<code>public void registerUser(String username, String email, String phoneNumber) {
    // Save user (simplified)
    userService.add(buildUser(username, email, phoneNumber));
    // Create message
    String registrationMessage = "User " + username + " has registered successfully.";
    // Send to queue
    rabbitTemplate.convertAndSend("registrationQueue", registrationMessage);
}
</code>

The consumer reads the message and sends the notification:

<code>@Service
public class NotificationService {
    @RabbitListener(queues = "registrationQueue")
    public void handleRegistrationNotification(String message) {
        System.out.println("Sending registration notification: " + message);
        sendSms(message);
        sendEmail(message);
    }
}
</code>

2. Decoupling

In micro‑service architectures, services often need to communicate. Using a message queue decouples them, avoiding tight coupling caused by direct API calls.

An e‑commerce platform’s payment service sends a stock‑deduction request via MQ instead of calling the inventory service directly.
<code>import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;

public class PaymentService {
    private DefaultMQProducer producer;
    public PaymentService() throws Exception {
        producer = new DefaultMQProducer("PaymentProducerGroup");
        producer.setNamesrvAddr("localhost:9876");
        producer.start();
    }
    public void processPayment(String orderId, int quantity) throws Exception {
        boolean paymentSuccessful = callPayment(orderId, quantity);
        if (paymentSuccessful) {
            String messageBody = "OrderId: " + orderId + ", Quantity: " + quantity;
            Message message = new Message("paymentTopic", "paymentTag", messageBody.getBytes());
            producer.send(message);
        }
    }
}
</code>
<code>public class InventoryService {
    private DefaultMQPushConsumer consumer;
    public InventoryService() throws Exception {
        consumer = new DefaultMQPushConsumer("InventoryConsumerGroup");
        consumer.setNamesrvAddr("localhost:9876");
        consumer.subscribe("paymentTopic", "paymentTag");
        consumer.registerMessageListener((msgs, context) -> {
            for (MessageExt msg : msgs) {
                String body = new String(msg.getBody());
                reduceStock(body);
            }
            return null;
        });
        consumer.start();
        System.out.println("InventoryService started...");
    }
}
</code>

3. Traffic Shaping (Peak‑Shaving)

During high‑concurrency events such as ticket booking or flash sales, a sudden traffic spike can overload services. Introducing a queue smooths the request rate, allowing the system to process a bounded number of requests per second.

4. Delayed Tasks

In an e‑commerce order flow, if an order remains unpaid for a certain period, a delayed message can automatically cancel the order after the timeout.
<code>@Service
public class OrderService {
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    public void createOrder(Order order) {
        long delay = order.getTimeout();
        rocketMQTemplate.syncSend("orderCancelTopic:delay" + delay,
            MessageBuilder.withPayload(order).build(),
            10000,
            (int) (delay / 1000));
    }
}
</code>
<code>@Component
@RocketMQMessageListener(topic = "orderCancelTopic", consumerGroup = "order-cancel-consumer-group")
public class OrderCancelListener implements RocketMQListener<Order> {
    @Override
    public void onMessage(Order order) {
        System.out.println("Cancelling order: " + order.getOrderId());
        // cancel logic here
    }
}
</code>

5. Log Collection

Message queues can forward logs from multiple micro‑services to a centralized logging system (e.g., ELK or Fluentd) for unified storage and analysis.

<code>// Produce log to Kafka topic "app-logs"
KafkaProducer<String, String> producer = new KafkaProducer<>(config);
String logMessage = "{\"level\": \"INFO\", \"message\": \"Application started\", \"timestamp\": \"2024-12-29T20:30:59\"}";
producer.send(new ProducerRecord<>("app-logs", "log-key", logMessage));
</code>
<code>@Service
public class LogConsumer {
    @KafkaListener(topics = "app-logs", groupId = "log-consumer-group")
    public void consumeLog(String logMessage) {
        System.out.println("Received log: " + logMessage);
    }
}
</code>

6. Distributed Transactions

MQ can act as a reliable bridge for implementing distributed transaction messages, ensuring consistency between services when a local transaction succeeds or fails.

7. Remote Invocation

Using RocketMQ, a custom remote‑call framework can provide features such as message tracing, multi‑center active‑active deployment, gray releases, traffic weighting, deduplication, and back‑pressure control.

8. Broadcast Notifications (Event‑Driven Messaging)

Message queues enable broadcasting events—such as order‑payment‑success—to multiple downstream systems (inventory, points, finance), each handling the event independently.

<code>// Publish order payment success event
String orderEventData = "{\"orderId\": 12345, \"userId\": 67890, \"amount\": 100.0, \"event\": \"ORDER_PAYMENT_SUCCESS\"}";
Message msg = new Message("order_event_topic", "order_payment_success", orderEventData.getBytes());
producer.send(msg);
</code>
<code>// Consumer example for inventory system
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
    for (Message msg : msgs) {
        String data = new String(msg.getBody());
        System.out.println("Inventory system received: " + data);
        // updateInventory(data);
    }
    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
</code>
Spring BootMessage Queuerocketmqasynchronous processingdistributed transactiondelayed taskstraffic shapingService Decoupling
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.