Mastering Delayed Tasks with RocketMQ and Spring Boot

This guide explains how to replace inefficient cron polling with RocketMQ's delayed message feature in Spring Boot, covering the core concept, configuration, producer and consumer implementation, testing, and how to customize delay levels for reliable time‑sensitive operations.

macrozheng
macrozheng
macrozheng
Mastering Delayed Tasks with RocketMQ and Spring Boot

Preface

In many applications you need to execute a task after a certain delay, such as automatically canceling an unpaid order after 30 minutes or giving a five‑star rating after 48 hours without user feedback. These are called delayed tasks .

The most common first thought is to use a cron job:

A cron job runs periodically (e.g., every 30 minutes) to find expired data and update its status. When the data volume is large, this requires paging and a loop of updates, which is inefficient.

Problems with the cron approach include:

Low efficiency when data volume is large.

Poor timeliness; a 1‑hour poll can cause up to an hour of delay.

Increasing poll frequency leads to redundant calculations and higher load.

Instead of cron, we can use RocketMQ delayed messages. When an order is created, send a delayed message to RocketMQ; after the delay the consumer checks the order status and cancels it if unpaid.

Implementation

The core idea of RocketMQ delayed queues is that all delayed messages are stored in a special topic (SCHEDULE_TOPIC_XXXX). Different delay levels correspond to different queue numbers. When the delay expires, a scheduled thread moves the message to the real target topic, making it visible to consumers.

Note: RocketMQ only supports a fixed set of delay levels, e.g.: private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

Below we combine Spring Boot with RocketMQ to send delayed messages.

Introduce RocketMQ dependency

<dependency>
  <groupId>org.apache.rocketmq</groupId>
  <artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>

Add RocketMQ configuration

rocketmq:
  name-server: 172.31.0.44:9876
  producer:
    group: delay-group

Write the producer

@Component
@Slf4j
public class DelayProduce {
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendDelayMessage(String topic, String message, int delayLevel) {
        SendResult sendResult = rocketMQTemplate.syncSend(topic, MessageBuilder.withPayload(message).build(), 2000, delayLevel);
        log.info("sendtime is {}", DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss").format(LocalDateTime.now()));
        log.info("sendResult is{}", sendResult);
    }
}

Write the consumer

@Slf4j
@Component
@RocketMQMessageListener(topic = "delay-topic", consumerGroup = "delay-group")
public class DelayConsumer implements RocketMQListener<String> {
    @Override
    public void onMessage(String message) {
        log.info("received message time is {}", DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss").format(LocalDateTime.now()));
        log.info("received message is {}", message);
    }
}

Test the producer

@RunWith(SpringRunner.class)
@SpringBootTest
public class DelayProduceTest {
    @Autowired
    private DelayProduce delayProduce;

    @Test
    public void sendDelayMessage() {
        delayProduce.sendDelayMessage("delay-topic", "Hello, JAVA日知录", 5);
    }
}

Setting delayLevel to 5 corresponds to a 1‑minute delay in RocketMQ.

Run results

Modify delay level

RocketMQ's delay levels can be edited to meet business needs, e.g., adding a 1‑day level.

Edit the broker configuration file and change the messageDelayLevel property

brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
storePathRootDir = /app/rocketmq/data
messageDelayLevel=90s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

After changing the first level to 90s, restart RocketMQ:

nohup sh mqbroker -n localhost:9876 -c ../conf/broker.conf &

Send a message using the new level 1 (90s)

public void sendDelayMessage() {
    delayProduce.sendDelayMessage("delay-topic", "Hello, JAVA日知录", 1);
}

Test and compare send/consume timestamps to verify the new delay works.

By comparing the send and consume times, you can confirm that the modified delay level takes effect.

Hope this helps!

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootRocketMQdelayed tasks
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

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.