簡體   English   中英

如何使用Rabbit綁定創建帶有事務的處理程序和DLQ?

[英]How to create Processor with Transaction and DLQ with Rabbit binding?

我才剛剛開始學習Spring Cloud Streams和Dataflow,我想了解一個重要的用例之一。 我創建了示例處理器Multiplier,它接收消息並將其重新發送5次以輸出。

@EnableBinding(Processor.class)
public class MultiplierProcessor {
    @Autowired
    private Source source;

    private int repeats = 5;

    @Transactional
    @StreamListener(Processor.INPUT)
    public void handle(String payload) {
        for (int i = 0; i < repeats; i++) {
            if(i == 4) {
                throw new RuntimeException("EXCEPTION");
            }
            source.output().send(new GenericMessage<>(payload));
        }
    }
}

您會看到在第5次發送此處理器之前崩潰。 為什么? 因為它可以(程序引發異常)。 在這種情況下,我想在Spring Cloud Stream上練習故障預防。

我要實現的是將輸入消息備份到DLQ中,並發送4條消息,這些消息在發送之前已還原並且不被下一個操作數使用(就像在普通JMS事務中一樣)。 我已經嘗試在處理器項目中定義以下屬性,但沒有成功。

spring.cloud.stream.bindings.output.producer.autoBindDlq=true
spring.cloud.stream.bindings.output.producer.republishToDlq=true
spring.cloud.stream.bindings.output.producer.transacted=true

spring.cloud.stream.bindings.input.consumer.autoBindDlq=true

你能告訴我是否可能,還有我在做什么錯? 對於某些示例,我將非常感激。

您的配置有幾個問題:

  • 在兔子特定的屬性中缺少.rabbit
  • 您需要組名和持久訂閱才能使用autoBindDlq
  • autoBindDlq不適用於輸出端

消費者必須進行交易,以便生產者發送在同一事務中執行。

我剛剛用1.0.2.RELEASE測試過:

spring.cloud.stream.bindings.output.destination=so8400out

spring.cloud.stream.rabbit.bindings.output.producer.transacted=true

spring.cloud.stream.bindings.input.destination=so8400in
spring.cloud.stream.bindings.input.group=so8400

spring.cloud.stream.rabbit.bindings.input.consumer.durableSubscription=true
spring.cloud.stream.rabbit.bindings.input.consumer.autoBindDlq=true
spring.cloud.stream.rabbit.bindings.input.consumer.transacted=true

並按預期工作。

編輯

實際上,不,發布的郵件不會回滾。 調查...

EDIT2

好; 它確實有效,但是您不能使用republishToDlq因為啟用該功能后,綁定程序會將失敗的消息發布到DLQ並提交事務。

如果為假,則將異常引發到容器,回滾事務,然后RabbitMQ將失敗的消息移至DLQ。

但是請注意,默認情況下會啟用重試(3次嘗試),因此,如果處理器在重試期間成功,則輸出中將出現重復項。

為了使此功能如您所願,您需要通過將最大嘗試次數設置為1來禁用重試(並且不要使用republishToDlq )。

EDIT3

好的,如果您想更好地控制錯誤的發布,則當此JIRA的修復程序應用於Spring AMQP時,此方法將起作用。

@SpringBootApplication
@EnableBinding({ Processor.class, So39018400Application.Errors.class })
public class So39018400Application {

    public static void main(String[] args) {
        SpringApplication.run(So39018400Application.class, args);
    }

    @Bean
    public Foo foo() {
        return new Foo();
    }

    public interface Errors {

        @Output("errors")
        MessageChannel errorChannel();

    }

    private static class Foo {

        @Autowired
        Source source;

        @Autowired
        Errors errors;

        @StreamListener(Processor.INPUT)
        public void handle (Message<byte[]> in) {
            try {
                source.output().send(new GenericMessage<>("foo"));
                source.output().send(new GenericMessage<>("foo"));
                throw new RuntimeException("foo");
            }
            catch (RuntimeException e) {
                errors.errorChannel().send(MessageBuilder.fromMessage(in)
                        .setHeader("foo", "bar") // add whatever you want, stack trace etc.
                        .build());
                throw e;
            }
        }

    }

}

具有屬性:

spring.cloud.stream.bindings.output.destination=so8400out

spring.cloud.stream.bindings.errors.destination=so8400errors
spring.cloud.stream.rabbit.bindings.errors.producer.transacted=false


spring.cloud.stream.rabbit.bindings.output.producer.transacted=true

spring.cloud.stream.bindings.input.destination=so8400in
spring.cloud.stream.bindings.input.group=so8400

spring.cloud.stream.rabbit.bindings.input.consumer.transacted=true
spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=false
spring.cloud.stream.bindings.input.consumer.max-attempts=1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM