Spring Integration AMQP - 尽管重试建议,仍在不断重试

时间:2016-12-05 21:27:08

标签: spring-integration spring-amqp

之前我已经非常成功地使用过Spring与JMS,但我们现在正在使用RabbitMQ / AMQP并且遇到一些错误处理问题。

我有一个int-amqp:inbound-channel-adapter,并设置了一个errorChannel来接收任何异常,这里一个ErrorTransformer类检查失败的Message的cause异常。然后根据异常的类型: -

  1. 禁止异常并转换为JSON对象,该对象可以作为解释失败的业务回复转至AMQP出站通道适配器。在这里,我想要消耗/确认原始消息。

  2. 或者重新抛出导致的异常,让RabbitMQ重新传递消息一定次数。

  3. 我发现重新投掷导致消息被连续重新传递,然后我读到有关StatefulRetryOperationsInterceptorFactoryBean,所以添加了一个建议链来重试3次,然后我得到了关于没有message-id的异常,所以还添加了一个'在建议链的开头有MissingMessageIdAdvice。

    尽管有这样的建议,我仍然会从errorChannel的ErrorTransformer重新抛出一个RuntimeException 连续重试。我只是使用默认值通过RabbitMQ管理员发布消息。不确定缺少消息ID是否会使其无法正常工作,如果是这样,我如何获取消息以获取ID? 我对以下几点之间的区别感到困惑: -

    A)ConditionalRejectingErrorHandler(我已设置为入站适配器的错误处理程序),它允许我提供customFatalExceptionStrategy来实现isFatal()。我相信fatal = true(意味着DISCARD)并消息被丢弃,但我怎么还能发送出站失败消息?

    B)我在入站适配器上使用的errorChannel,我用它来检查Exception并转换为出站失败响应消息。在这里我想我可以抛出AmqpRejectAndDontRequeueException,但是为什么还有ConditionalRejectingErrorHandler呢?并将使用AmqpRejectAndDontRequeueException工作

         <int-amqp:inbound-channel-adapter id="amqpInRequestPatternValuation"  channel="requestAmqpIn" channel-transacted="true"  transaction-manager="transactionManager"
             queue-names="requestQueue" error-channel="patternValuationErrorChannel" connection-factory="connectionFactory"
             receive-timeout="59000" concurrent-consumers="1"
             advice-chain="retryChain" error-handler="customErrorHandler" />
    
     <bean id="customErrorHandler" class="org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler">
             <constructor-arg ref="customFatalExceptionStrategy"/>
      </bean>                             
    
    
    <bean id="customFatalExceptionStrategy" class="abc.common.CustomFatalExceptionStrategy"/>
    
    
    
      <!-- ADVICE CHAIN FOR CONTROLLING NUMBER OF RE-TRIES before sending to DLQ (or discarding if no DLQ) without this any re-queued fatal message will retry forever  -->
    
      <util:list id="retryChain">
          <bean class="org.springframework.amqp.rabbit.retry.MissingMessageIdAdvice">
              <constructor-arg>
                  <bean class="org.springframework.retry.policy.MapRetryContextCache" />
              </constructor-arg>
          </bean>
          <ref bean="retryInterceptor" />
      </util:list>
    
    <bean id="retryInterceptor"
        class="org.springframework.amqp.rabbit.config.StatefulRetryOperationsInterceptorFactoryBean">
        <property name="retryOperations" ref="retryTemplate" />
        <property name="messageRecoverer" ref="messageRecoverer"/>
    </bean>
    
     <bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
       <property name="retryPolicy" ref="simpleRetryPolicy" />
       <property name="backOffPolicy">
              <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                     <property name="initialInterval" value="10000" />
              </bean>
       </property>
    </bean>
    
      <bean id="simpleRetryPolicy" class="org.springframework.retry.policy.SimpleRetryPolicy">
        <property name="maxAttempts" value="3" />
    </bean>
    

2 个答案:

答案 0 :(得分:0)

您必须使用RejectAndDontRequeueRecoverer在重试结束时停止重新投放:

 * MessageRecover that causes the listener container to reject
 * the message without requeuing. This enables failed messages
 * to be sent to a Dead Letter Exchange/Queue, if the broker is
 * so configured.

是的,messageId对于重试用例非常重要。

如果您无法在发送过程中手动提供,则可以注入自定义MessageKeyGenerator策略以确定邮件中的唯一密钥。

答案 1 :(得分:0)

我从未到过发布解决方案,所以在这里。

一旦我将重试建议链配置到AMQP入站通道适配器,该适配器必须包含RejectAndDontRequeueRecoverer的messageRecoverer(我相信它也是dafault)。我缺少的重点是确保发件人发送邮件时包含message_id。因此,如果通过RabbitMQ管理控制台发布,我需要包含预定义的message_id属性并提供值。

使用'MissingMessageIdAdvice'没有帮助(因此我删除了),因为它会在每次重新传递消息时生成不同的message_id,导致重试计数不递增,因为每次传递被认为与最后一次不同