如何将普通队列异常消息路由到死信队列

如何将普通队列异常消息路由到死信队列

在RabbitMQ中,我们经常需要处理异常消息,特别是当消息处理失败时。一个常见的用例是将异常消息路由到死信队列,以便稍后重新处理或进一步分析。在本篇博客中,我们将演示如何配置RabbitMQ和Spring Boot,以便将普通队列中的异常消息自动路由到死信队列。

步骤1:创建Spring Boot项目

首先,创建一个Spring Boot项目并添加以下依赖:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.0</version>
    </dependency>
</dependencies>

步骤2:配置RabbitMQ和队列

在`application.yml文件中,配置RabbitMQ连接信息:

properties 复制代码
spring:
  #给项目来个名字
  application:
    name: rabbitmq-provider
  #配置rabbitMq 服务器
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: root
    password: 123456
    #虚拟host 可以不设置,使用server默认host
    virtual-host: /cdn
      #确认消息已发送到交换机(Exchange)
      #确认消息已发送到队列(Queue)
    publisher-returns: true
    listener:
      simple:
        acknowledge-mode: auto
        retry:
          #enabled:开启失败重试
          enabled: true
          #第一次重试的间隔时长
          initial-interval: 1000ms
          #最长重试间隔,超过这个间隔将不再重试
          max-interval: 300000ms
          #下次重试间隔的倍数,此处是2即下次重试间隔是上次的2倍
          multiplier: 2
          max-attempts: 4
        default-requeue-rejected: false  # 达到重试次数进入死信队列
    publisher-confirm-type: none

然后,创建一个Spring组件,它将包括配置RabbitMQ队列和消息监听器:

java 复制代码
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.hutool.core.util.RandomUtil;

@RestController
public class ExceptionToDead {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Bean
    public Queue normalQueue() {
        return QueueBuilder.durable("my-normal-queue")
                .withArgument("x-dead-letter-exchange", "my-dead-letter-exchange")
                .withArgument("x-dead-letter-routing-key", "my-dead-letter-routing-key")
                .build();
    }

    @Bean
    public DirectExchange normalExchange() {
        return new DirectExchange("my-normal-exchange");
    }

    @Bean
    public Binding normalBinding(Queue normalQueue, DirectExchange normalExchange) {
        return BindingBuilder.bind(normalQueue).to(normalExchange).with("my-normal-routing-key");
    }

    @Bean
    public DirectExchange deadLetterExchange() {
        return new DirectExchange("my-dead-letter-exchange");
    }

    @Bean
    public Queue deadLetterQueue() {
        return QueueBuilder.durable("my-dead-letter-queue").build();
    }

    @Bean
    public Binding deadLetterBinding(Queue deadLetterQueue, DirectExchange deadLetterExchange) {
        return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("my-dead-letter-routing-key");
    }

    @RabbitListener(queues = "my-normal-queue")
    public void receiveFromNormalQueue(Integer message) {
        System.out.println("正常队列收到消息: " + message);
        if (message % 2 == 0) {
            int a = 1 / 0; // 引发异常
        }
    }

    @RabbitListener(queues = "my-dead-letter-queue")
    public void receiveFromDeadLetterQueue(Integer message) {
        System.out.println("死信队列收到消息: " + message);
    }

    @GetMapping("send")
    public void send() {
        int number = RandomUtil.randomInt(0, 100);
        rabbitTemplate.convertAndSend("my-normal-exchange", "my-normal-routing-key", number);
    }

    @GetMapping("b")
    public void b() {
        int number = RandomUtil.randomInt(0, 100);
        rabbitTemplate.convertAndSend("simple-key", number);
    }
}

在这段代码中,我们创建了一个名为my-normal-queue的队列,它将异常消息路由到my-dead-letter-exchange交换机,然后再路由到my-dead-letter-queue队列。我们还创建了相应的交换机和绑定。

注意: 自动确认的时候 ,达到重试次数之后就会路由到绑定的死信,否则消息会丢失

​ 手动确认的时候,消费时候在需要的位置channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false); 消息才会路由到死信,否则消息会积压

步骤3:监听异常消息并触发死信路由

在上述代码中,我们使用@RabbitListener注解来监听my-normal-queue队列。当消息处理失败时(在这里,我们模拟了一个条件,如果消息为偶数,则引发异常),它将被路由到死信队列。

步骤4:触发异常消息

最后,我们在/send端点上创建了一个HTTP请求,它将发送一个随机整数到my-normal-queue队列。如果随机整数

相关推荐
Asthenia04123 小时前
浏览器缓存机制深度解析:电商场景下的性能优化实践
后端
databook4 小时前
『Python底层原理』--Python对象系统探秘
后端·python
超爱吃士力架5 小时前
MySQL 中的回表是什么?
java·后端·面试
追逐时光者5 小时前
Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
后端·.net
典龙3306 小时前
如何使用springboot项目如何实现小程序里面商品的浏览记录功能案例
spring boot
苏三说技术6 小时前
10亿数据,如何迁移?
后端
bobz9656 小时前
openvpn 显示已经建立,但是 ping 不通
后端
customer087 小时前
【开源免费】基于SpringBoot+Vue.JS个人博客系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
qq_459238497 小时前
SpringBoot整合Redis和Redision锁
spring boot·redis·后端
灰色人生qwer7 小时前
SpringBoot 项目配置日志输出
java·spring boot·后端