21人参与 • 2026-03-05 • Redis
redisson的rdelayedqueue是实现订单到期关闭的利器,它比定时任务更精准、比redis过期监听更可靠。其核心原理是利用redis的**有序集合(sorted set)和发布/订阅(pub/sub)**功能,在分布式环境下可靠地执行延迟任务。
接下来,我们结合java代码,一步步来看如何实现。
在用户下单成功后,我们需要做的不是立即启动一个计时器,而是将这笔订单的id作为一条“延迟消息”发送出去。
import org.redisson.api.rblockingqueue;
import org.redisson.api.rdelayedqueue;
import org.redisson.api.redissonclient;
import org.springframework.stereotype.service;
import javax.annotation.resource;
import java.util.concurrent.timeunit;
@service
public class orderservice {
@resource
private redissonclient redissonclient;
// 队列的名称,可以理解为用于存放待关闭订单的“信箱”
private static final string order_queue_key = "order-close-queue";
public void createorder(order order) {
// 1. 保存订单到数据库 (省略具体逻辑)
savetodb(order);
log.info("订单 [{}] 创建成功,等待支付...", order.getid());
// 2. 将订单id放入延迟队列,设置30分钟后“爆炸”
try {
// 获取一个阻塞队列,这是消费者最终要监听的目标队列
rblockingqueue<string> blockingqueue = redissonclient.getblockingqueue(order_queue_key);
// 基于阻塞队列,创建一个延迟队列
rdelayedqueue<string> delayedqueue = redissonclient.getdelayedqueue(blockingqueue);
// 将订单id放入延迟队列,延迟30分钟
delayedqueue.offer(order.getid().tostring(), 30, timeunit.minutes);
log.info("订单 [{}] 已放入延迟队列,30分钟后将自动关闭", order.getid());
} catch (exception e) {
log.error("放入延迟队列失败", e);
// 这里可以考虑补偿机制,比如记录日志后由定时任务兜底
}
}
}核心逻辑:生产者调用delayedqueue.offer(),将任务(订单id)和延迟时间(30分钟)告诉redisson。redisson客户端会把这个任务连同计算好的执行时间戳,一起存到redis的一个**有序集合(zset)**中,并以时间戳作为排序的分数(score)。
我们需要一个后台任务一直监听,一旦有订单到期,立刻执行关闭操作。
import org.redisson.api.rblockingqueue;
import org.redisson.api.redissonclient;
import org.springframework.boot.commandlinerunner;
import org.springframework.stereotype.component;
import javax.annotation.resource;
@component
public class ordercloselistener implements commandlinerunner {
@resource
private redissonclient redissonclient;
@resource
private orderservice orderservice; // 注入你的订单service
private static final string order_queue_key = "order-close-queue";
@override
public void run(string... args) throws exception {
// 程序启动后,在一个独立的线程中监听队列
new thread(() -> {
log.info("订单关闭监听线程已启动,等待到期订单...");
// 获取与生产者相同的阻塞队列
rblockingqueue<string> blockingqueue = redissonclient.getblockingqueue(order_queue_key);
// 注意:这里必须调用一次getdelayedqueue,目的是在消费端也初始化相关的监听器
// 虽然不调用也能工作,但官方推荐调用以保证可靠性
redissonclient.getdelayedqueue(blockingqueue);
while (true) {
try {
// 阻塞等待,直到有订单到期。take()方法会一直阻塞直到拿到数据
string orderid = blockingqueue.take();
log.info("收到到期订单id:{},开始执行关闭操作", orderid);
// 执行真正的关单业务逻辑
orderservice.closeexpiredorder(long.parselong(orderid));
} catch (interruptedexception e) {
log.error("监听线程被中断", e);
thread.currentthread().interrupt();
break; // 线程中断时退出循环
} catch (exception e) {
log.error("处理到期订单时发生错误", e);
// 防止单个消息处理失败导致循环中断,继续监听下一个
}
}
}, "orderclose-listener").start();
}
}核心逻辑:消费者通过blockingqueue.take()阻塞地从redis的**目标队列(list)**中获取消息。当一个任务在zset中的时间戳小于当前时间,redisson的后台线程就会自动把它从zset移动到目标list中。这时,take()方法就会立即返回,拿到订单id,执行关闭逻辑。
你可能会好奇,redisson是如何精准地将到期任务从zset移到list的?这背后有一个巧妙的设计:
redisson为每个延迟队列启动了一个后台轮询线程(基于netty的时间轮实现)。这个线程会:
所以,整个过程就像有一个精准的“闹钟”在帮你管理这些任务。
order-close-queue)即可。多个消费者实例可以同时take同一个队列,实现任务的负载均衡。config.setscaninterval(2000)来缩短轮询间隔(单位为毫秒),但会略微增加redis的压力。到此这篇关于redisson延迟队列实现订单关闭的操作方法的文章就介绍到这了,更多相关redisson延迟队列订单关闭内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论