Backend Development 16 min read

Implementing Automatic Order Closure in E‑commerce: Scheduled Tasks, RocketMQ Delay Queue, RabbitMQ Dead‑Letter Queue, Time Wheel Algorithm, and Redis Expiration

The article explains how to automatically close unpaid e‑commerce orders by comparing five approaches—simple scheduled tasks, RocketMQ delayed messages, RabbitMQ dead‑letter queues, a time‑wheel algorithm, and Redis key‑expiration listeners—detailing their advantages, drawbacks, and providing Java code examples for each method.

Top Architect
Top Architect
Top Architect
Implementing Automatic Order Closure in E‑commerce: Scheduled Tasks, RocketMQ Delay Queue, RabbitMQ Dead‑Letter Queue, Time Wheel Algorithm, and Redis Expiration

In e‑commerce and payment systems, orders that remain unpaid after a certain period must be closed automatically; this article explores five practical solutions and their implementation details.

General approaches

Scheduled task that scans orders at fixed intervals.

RocketMQ delayed queue.

RabbitMQ dead‑letter queue.

Time‑wheel algorithm.

Redis expiration listener.

1. Scheduled task (least recommended)

Using a cron‑like job to run every 10 minutes can cause up to a 10‑minute delay and high I/O due to frequent scans.

2. RocketMQ delayed queue

RocketMQ supports 18 predefined delay levels (e.g., 1s, 5s, …, 2h). A producer sets the delay level and sends the message; the consumer receives it after the configured delay.

/**
 * Push delayed message
 */
public boolean sendMessage(String topic, String body, String producerGroup) {
    try {
        Message recordMsg = new Message(topic, body.getBytes());
        producer.setProducerGroup(producerGroup);
        // set delay level, 14 corresponds to 10 minutes
        recordMsg.setDelayTimeLevel(14);
        SendResult sendResult = producer.send(recordMsg);
        log.info("发送延迟消息结果:======sendResult:{}", sendResult);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        log.error("延迟消息队列推送消息异常:{},推送内容:{}", e.getMessage(), body);
    }
    return false;
}

3. RabbitMQ dead‑letter queue

RabbitMQ does not have native delayed queues; it uses a dead‑letter exchange combined with message TTL to achieve delay. The workflow includes creating a normal exchange (named delay ), an auto‑expire queue, and a final processing queue.

String msg = "hello word";
MessageProperties messageProperties = newMessageProperties();
messageProperties.setExpiration("6000");
Message message = newMessage(msg.getBytes(), messageProperties);
rabbitTemplate.convertAndSend("delay", "delay", message);

4. Time‑wheel algorithm

A circular slot array (e.g., 3600 slots for one‑hour resolution) stores tasks; a timer moves a pointer each second, executing tasks whose cycleNum reaches zero. This provides O(1) scheduling and second‑level precision.

5. Redis key‑expiration listener

By enabling notify-keyspace-events Ex in redis.windows.conf , a KeyExpirationEventMessageListener can react to expired keys (e.g., order_12345 ) and update the order status in the database.

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Override
    public void onMessage(Message message, byte[] pattern) {
        try {
            String key = message.toString();
            if (key != null && key.startsWith("order_")) {
                String orderNo = key.substring(6);
                QueryWrapper
qw = new QueryWrapper<>();
                qw.eq("order_no", orderNo);
                OrderInfoEntity order = orderInfoMapper.selectOne(qw);
                if (order != null && order.getOrderState() == 0) { // pending payment
                    order.setOrderState(4); // cancelled
                    orderInfoMapper.updateById(order);
                    log.info("订单号为【" + orderNo + "】超时未支付-自动修改为已取消状态");
                }
            }
        } catch (Exception e) {
            log.error("【修改支付订单过期状态异常】:" + e.getMessage());
        }
    }
}

Conclusion

Each method has trade‑offs; the time‑wheel and Redis listener provide high precision with low overhead, while RocketMQ and RabbitMQ rely on external middleware. Choose the solution that fits your stack and latency requirements.

javaRedisMessage QueueRabbitMQrocketmqScheduled Task@Order
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.