【问题标题】:Configuration to handle Dead-letter queue处理死信队列的配置
【发布时间】:2019-12-09 18:52:15
【问题描述】:

我有一个项目使用 Spring Cloud Streams - RabbitMQ 在微服务中交换消息。对我的项目至关重要的一件事是我不能丢失任何信息。

为了尽量减少失败,我做了以下计划:

  • 对队列中的消息使用默认重试方法
  • 配置死信队列以在一段时间后再次将消息放入队列
  • 为避免无限循环,仅允许将消息从死信队列重新发布到常规消息队列的几次(例如 5 次)。

前两项我相信我可以使用以下配置完成:

#dlx/dlq setup - retry dead letter 5 minutes later (300000ms later)
spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true
spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=true
spring.cloud.stream.rabbit.bindings.input.consumer.dlq-ttl=300000
spring.cloud.stream.rabbit.bindings.input.consumer.dlq-dead-letter-exchange=

#input
spring.cloud.stream.bindings.myInput.destination=my-queue
spring.cloud.stream.bindings.myInput.group=my-group

但是,我找不到searching on this reference guide 如何做我想做的事(主要是如何配置从死信队列重新发布的最大数量)。我不完全确定我走在正确的道路上 - 也许我应该手动创建第二个队列并编写我想要的代码,并且只将死信留给完全失败的消息(我必须定期检查并手动处理,因为我的系统不应该丢失任何消息)...

我是这些框架的新手,希望您能帮助我配置我的框架...

【问题讨论】:

    标签: java configuration rabbitmq spring-cloud-stream dead-letter


    【解决方案1】:

    This documentation for the rabbit binder 展示了如何在多次重试失败后向某个停车场队列发布死信。

    @SpringBootApplication
    public class ReRouteDlqApplication {
    
        private static final String ORIGINAL_QUEUE = "so8400in.so8400";
    
        private static final String DLQ = ORIGINAL_QUEUE + ".dlq";
    
        private static final String PARKING_LOT = ORIGINAL_QUEUE + ".parkingLot";
    
        private static final String X_RETRIES_HEADER = "x-retries";
    
        public static void main(String[] args) throws Exception {
            ConfigurableApplicationContext context = SpringApplication.run(ReRouteDlqApplication.class, args);
            System.out.println("Hit enter to terminate");
            System.in.read();
            context.close();
        }
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @RabbitListener(queues = DLQ)
        public void rePublish(Message failedMessage) {
            Integer retriesHeader = (Integer) failedMessage.getMessageProperties().getHeaders().get(X_RETRIES_HEADER);
            if (retriesHeader == null) {
                retriesHeader = Integer.valueOf(0);
            }
            if (retriesHeader < 3) {
                failedMessage.getMessageProperties().getHeaders().put(X_RETRIES_HEADER, retriesHeader + 1);
                this.rabbitTemplate.send(ORIGINAL_QUEUE, failedMessage);
            }
            else {
                this.rabbitTemplate.send(PARKING_LOT, failedMessage);
            }
        }
    
        @Bean
        public Queue parkingLot() {
            return new Queue(PARKING_LOT);
        }
    
    }
    

    第二个例子展示了如何使用延迟交换插件来延迟重试。

    @SpringBootApplication
    public class ReRouteDlqApplication {
    
        private static final String ORIGINAL_QUEUE = "so8400in.so8400";
    
        private static final String DLQ = ORIGINAL_QUEUE + ".dlq";
    
        private static final String PARKING_LOT = ORIGINAL_QUEUE + ".parkingLot";
    
        private static final String X_RETRIES_HEADER = "x-retries";
    
        private static final String DELAY_EXCHANGE = "dlqReRouter";
    
        public static void main(String[] args) throws Exception {
            ConfigurableApplicationContext context = SpringApplication.run(ReRouteDlqApplication.class, args);
            System.out.println("Hit enter to terminate");
            System.in.read();
            context.close();
        }
    
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @RabbitListener(queues = DLQ)
        public void rePublish(Message failedMessage) {
            Map<String, Object> headers = failedMessage.getMessageProperties().getHeaders();
            Integer retriesHeader = (Integer) headers.get(X_RETRIES_HEADER);
            if (retriesHeader == null) {
                retriesHeader = Integer.valueOf(0);
            }
            if (retriesHeader < 3) {
                headers.put(X_RETRIES_HEADER, retriesHeader + 1);
                headers.put("x-delay", 5000 * retriesHeader);
                this.rabbitTemplate.send(DELAY_EXCHANGE, ORIGINAL_QUEUE, failedMessage);
            }
            else {
                this.rabbitTemplate.send(PARKING_LOT, failedMessage);
            }
        }
    
        @Bean
        public DirectExchange delayExchange() {
            DirectExchange exchange = new DirectExchange(DELAY_EXCHANGE);
            exchange.setDelayed(true);
            return exchange;
        }
    
        @Bean
        public Binding bindOriginalToDelay() {
            return BindingBuilder.bind(new Queue(ORIGINAL_QUEUE)).to(delayExchange()).with(ORIGINAL_QUEUE);
        }
    
        @Bean
        public Queue parkingLot() {
            return new Queue(PARKING_LOT);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2013-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 2021-02-18
      • 2012-10-19
      • 2020-02-14
      相关资源
      最近更新 更多