【问题标题】:Spring Integration ( Retry Strategy)Spring集成(重试策略)
【发布时间】:2020-08-26 11:36:05
【问题描述】:

我想用 Spring 集成创建一个简单的 IntegrationFlow,但遇到了困难。

我想创建一个集成流,从 Rabbit Mq 中的队列获取消息并将消息发布到端点 Rest。

我正在处理的问题是,当请求失败时,它会继续无休止地重试,我该如何在这段代码中实现重试策略? 例如,我想要 3 次重试,第一次在 1 秒后重试,第二次在 5 秒后重试,第三次在 1 分钟后重试。


        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setQueueNames(BOUTIQUE_QUEUE_NAME);
        container.setAcknowledgeMode(AcknowledgeMode.AUTO);
        return IntegrationFlows.from(Amqp.inboundAdapter(container)) /* Get Message from RabbitMQ */
                .handle(msg ->
                {
                    String msgString = new String((byte[]) msg.getPayload(), StandardCharsets.UTF_8);
                    HttpEntity<String> requestBody = new HttpEntity<String>(msgString, headers);
                    restTemplate.postForObject(ENDPOINT_LOCAL_URL, requestBody, String.class);
                    System.out.println(msgString);
                   
                })
                .get();
    }

【问题讨论】:

    标签: spring spring-integration spring-amqp spring-integration-dsl


    【解决方案1】:

    向侦听器容器的建议链添加重试拦截器。见https://docs.spring.io/spring-amqp/docs/2.2.10.RELEASE/reference/html/#retryhttps://docs.spring.io/spring-amqp/docs/2.2.10.RELEASE/reference/html/#async-listeners

    编辑

    @SpringBootApplication
    public class So63596805Application {
    
        private static final Logger LOG = LoggerFactory.getLogger(So63596805Application.class);
    
        public static void main(String[] args) {
            SpringApplication.run(So63596805Application.class, args);
        }
    
        @Bean
        IntegrationFlow flow(SimpleRabbitListenerContainerFactory factory, RabbitTemplate template) {
            SimpleMessageListenerContainer container = factory.createListenerContainer();
            container.setQueueNames("foo");
            container.setAdviceChain(RetryInterceptorBuilder.stateless()
                    .maxAttempts(5)
                    .backOffOptions(1000, 2.0, 10000)
                    .recoverer((msg, cause) -> LOG.info("Retries exhausted for " + msg))
                    .build());
            return IntegrationFlows.from(Amqp.inboundAdapter(container))
                    .handle(msg -> {
                        LOG.info(msg.getPayload().toString());
                        throw new RuntimeException("test");
                    })
                    .get();
        }
    
    }
    

    这使用指数退避策略。

    如果你使用

    .maxAttempts(4)
    .backOffOptions(1000, 5.0, 60000)
    

    您将在 1、5 和 25 秒后重试 3 次。

    1000, 8.0, 60000 会给你 1、8 和 60 秒。

    如果您必须有自己的规格(1、5、60),则需要自定义 BackOffPolicy。

    【讨论】:

    • 谢谢你的回答,你有请一个例子(带代码)吗? ,我在没有示例的情况下无法理解实现,我应该如何在 Flow 中注入 StatefulRetryOperationsInterceptor ?
    • 我加了一个例子。
    • 谢谢加里! ,最后一件事,我看到 spring 在 5 次重试后类似于消息,即使它们都是失败的重试。通常应该是 Nack,我错了吗?
    • 使用无状态重试,重试全部在内存中完成,无需与代理交互。使用有状态重试,消息将在每次失败时被 nack 并重新传递(在预取之后)。有状态重试需要唯一的 messageId 属性才能工作。框架提供了几个恢复器。 RepublishMessageRecoverer 将失败的消息(带有诊断)发送到另一个队列。 RejectAndDontRequeueRecoverer 允许代理将失败的消息发送到 DLQ(如果这样配置)。默认恢复器只记录消息(就像在我的示例中一样)。
    猜你喜欢
    • 1970-01-01
    • 2019-05-08
    • 2012-03-15
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    相关资源
    最近更新 更多