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.
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-groupWrite 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 2hAfter 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!
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
