RabbitMQ延时任务:订单超时取消

在电商项目中,我们经常会遇到这样的需求:客户下单成功后,在一定的时间内未能按时(具体时间由业务规则决定)支付,需要将订单自动取消,释放占用的商品库存。类似于这样的需求(延时任务),我们该怎样解决呢?本文主要分享我项目中实际应用的方式

基于RabbitMQ实现

死信队列(Dead Letter Queue)

当消息在队列中变成死信(消费者无法正常处理的消息)之后,它会被重新投递到死信交换机,死信交换机上绑定的消费队列就是死信队列 RabbitMQ的 Queue 可以配置 x-dead-letter-exchangex-dead-letter-routing-key(可选)两个参数,用来控制队列内出现死信时,则按照这两个参数重新投递

可以看到我们正常的队列,指定了死信交换机和路由Key

核心思路:将设置了过期时间的消息,投放到没有消费者的队列,当消息过期后就会成为死信,死信消息会被投放到死信交换机,我们就可以通过死信队列来消费处理,从而达到延时任务的效果

但是这种方案只适用于过期时间统一的场景(不然实现起来会麻烦,也很复杂),如果过期时间不一样,那么就会出现过期时间长的消息阻塞过期时间短的消息(队列是先进先出的,每次只会判断队头的消息是否过期)。

延时消息插件rabbitmq_delayed_message_exchange

RabbitMQ可以不用死信队列也能实现延迟消息,那就是基于官方出的rabbitmq_delayed_message_exchange插件 (ps:怎么安装插件,网上有教程可以搜一下)

需要注意的是该插件支持的最大延长时间是(2^32)-1 毫秒,大约49天

首先我们要声明一个x-delayed-message类型的交换机

核心思路:通过这个交换机的消息不会立即进入到x-delayed-message队列中,而是存放到了一个基于Erlang开发的Mnesia数据库中,然后通过一个定时器去查询需要被投递的消息(判断消息过期时间),再把他们投递到x-delayed-message队列中

到这我们已经了解了RabbitMQ实现延时任务的核心,在实际的项目中,我们还需要一系列的手段来保证业务的正常进行

  • 消息丢失

通过任务表,来记录我们的延时任务

  • 消息重复投递或重复消费

任务表中我们记录了任务的执行状态,可以根据执行状态来避免此类问题

sql 复制代码
create table job_info
(
    id                 varchar(32)                        not null comment 'ID'
        primary key,
    job_no             varchar(64)                        not null comment '任务编号',
    tx_no              varchar(225)                       null comment '任务流水号',
    job_data           json                               null comment '任务数据',
    job_headers        varchar(512)                       null comment '任务数据头',
    job_execute_res    text                               null comment '任务执行结果',
    job_execute_date   datetime                           null comment '任务执行日期',
    job_status         varchar(16)                        null comment '任务状态',
    job_execute_status varchar(16)                        null comment '任务执行状态',
    call_url           varchar(255)                       null comment '执行调度地址',
    call_type          varchar(16)                        null comment '调度类型',
    call_retry         varchar(16)                        null comment '调度重试',
    remark             text                               null comment '备注',
    status             varchar(4)                         null
)
    comment '定时任务表' collate = utf8_bin;

总结

除了基于RabbitMQ实现延时任务,还有其它很多种包括像定时任务、JDK延迟队列、redis、RocketMQ等等来实现,至于选哪种方式,还是应该由具体的业务来决定(适合最重要)。不过如果遇到开头我说的场景,还是推荐基于RabbitMQ插件这种方式。

相关推荐
夜月行者1 小时前
如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue
java·后端·ssm
Yvemil71 小时前
RabbitMQ 入门到精通指南
开发语言·后端·ruby
niu_sama1 小时前
仿RabbitMQ实现消息队列三种主题的调试及源码
分布式·rabbitmq
鸡c1 小时前
rabbitMq------客户端模块
分布式·rabbitmq·ruby
sdg_advance1 小时前
Spring Cloud之OpenFeign的具体实践
后端·spring cloud·openfeign
猿java2 小时前
使用 Kafka面临的挑战
java·后端·kafka
碳苯2 小时前
【rCore OS 开源操作系统】Rust 枚举与模式匹配
开发语言·人工智能·后端·rust·操作系统·os
kylinxjd2 小时前
spring boot发送邮件
java·spring boot·后端·发送email邮件
2401_857439696 小时前
Spring Boot新闻推荐系统:用户体验优化
spring boot·后端·ux
进击的女IT6 小时前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端