侧边栏壁纸
博主头像
拾荒的小海螺博主等级

只有想不到的,没有做不到的

  • 累计撰写 194 篇文章
  • 累计创建 19 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南

拾荒的小海螺
2024-10-28 / 0 评论 / 0 点赞 / 14 阅读 / 5657 字

1、简述

在支付系统中,订单支付的超时自动撤销是一个非常常见的业务场景。通常用户未在规定时间内完成支付,系统会自动取消订单,释放相应的资源。本文将通过利用 RabbitMQ 的 死信队列(Dead Letter Queue, DLQ)来实现支付超时自动撤销功能,并详细讲解如何在 Java 中进行实现。

1730103178109.jpg

2、什么是死信队列?

死信队列是 RabbitMQ 中的一个重要功能,当消息在某个队列中变成“死信”时,可以被发送到另一个特殊的队列,这个队列就是死信队列。消息变成死信的情况有三种:

  • 消息被拒绝(basic.reject 或 basic.nack),并且 requeue=false。
  • 消息的 TTL(Time to Live)过期。
  • 队列达到最大长度,无法再存入新消息。

通过死信队列,我们可以处理一些特殊的业务逻辑,例如订单支付超时自动撤销。

3、实现过程

我们将为每个新创建的支付订单设置一个超时时间(例如 30 分钟),在订单支付的过程中将订单的消息发送到 RabbitMQ。消息在 RabbitMQ 中设置一定的 TTL(生存时间)。如果用户在超时时间内完成支付,消息会被正常处理;如果超时未支付,消息会成为“死信”,被转移到死信队列,从而触发订单撤销的逻辑。

3.1 环境准备

首先,在 pom.xml 中添加 RabbitMQ 相关依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

3.2 RabbitMQ 配置

在 application.yml 中添加 RabbitMQ 的连接配置:

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

3.3 配置普通队列和死信队列

我们需要配置两个队列,一个是正常的支付订单队列,另一个是死信队列。

  • 支付订单队列:用于接收支付订单的消息。
  • 死信队列:接收从支付订单队列中转移过来的超时未处理的消息。
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    // 正常交换机
    @Bean
    public DirectExchange orderExchange() {
        return new DirectExchange("order-exchange");
    }

    // 死信交换机
    @Bean
    public DirectExchange deadLetterExchange() {
        return new DirectExchange("dead-letter-exchange");
    }

    // 正常队列
    @Bean
    public Queue orderQueue() {
        return QueueBuilder.durable("order-queue")
                .withArgument("x-dead-letter-exchange", "dead-letter-exchange") // 绑定死信交换机
                .withArgument("x-dead-letter-routing-key", "dead-letter-routing-key") // 死信路由键
                .withArgument("x-message-ttl", 1800000) // 消息的TTL(30分钟)
                .build();
    }

    // 死信队列
    @Bean
    public Queue deadLetterQueue() {
        return QueueBuilder.durable("dead-letter-queue").build();
    }

    // 绑定正常队列和交换机
    @Bean
    public Binding orderBinding(Queue orderQueue, DirectExchange orderExchange) {
        return BindingBuilder.bind(orderQueue).to(orderExchange).with("order-routing-key");
    }

    // 绑定死信队列和死信交换机
    @Bean
    public Binding deadLetterBinding(Queue deadLetterQueue, DirectExchange deadLetterExchange) {
        return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("dead-letter-routing-key");
    }
}

3.4 发送订单支付消息

在订单创建时,我们将消息发送到 RabbitMQ,设置 TTL(超时时间):

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void createOrder(String orderId) {
        // 模拟创建订单的逻辑
        System.out.println("订单创建成功,订单ID:" + orderId);

        // 发送订单消息到RabbitMQ
        rabbitTemplate.convertAndSend("order-exchange", "order-routing-key", orderId);
        System.out.println("订单消息已发送,等待支付超时或支付完成处理...");
    }
}

3.5 监听死信队列,实现超时自动撤销订单

当订单超时未支付,消息将转移到死信队列,我们通过监听死信队列,实现订单撤销逻辑:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class DeadLetterQueueListener {

    @RabbitListener(queues = "dead-letter-queue")
    public void handleExpiredOrder(String orderId) {
        // 处理超时订单撤销的逻辑
        System.out.println("订单支付超时,自动撤销订单,订单ID:" + orderId);
        // TODO: 更新数据库订单状态为已取消
    }
}

4、总结

通过使用 RabbitMQ 的死信队列,我们可以轻松实现支付超时自动撤销的功能。具体流程如下:

  • 创建订单时,将订单消息发送到 RabbitMQ,并为消息设置 TTL。
  • 如果用户在规定时间内完成支付,系统处理消息,订单正常完成。
  • 如果消息在 TTL 时间内未被处理,消息进入死信队列,触发自动撤销逻辑。

利用 RabbitMQ 死信队列可以确保超时订单得到及时处理,避免资源浪费,同时还能保证系统的高并发处理能力。

这套方案可以扩展应用于任何有类似超时要求的业务场景,如购物车超时、订单确认超时等。

0

评论区