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

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

基于RabbitMQ实现

死信队列(Dead Letter Queue)

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

image.png

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

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

image.png

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

延时消息插件rabbitmq_delayed_message_exchange

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

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

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

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

image.png

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

  • 消息丢失

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

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

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

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插件这种方式。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值