为什么重试策略不适用于Spring集成拆分器?

时间:2018-09-27 17:54:21

标签: spring spring-integration spring-retry

重试策略不起作用

<task:executor id="ticketSourceExc" pool-size="1"
        queue-capacity="0" rejection-policy="CALLER_RUNS" />
    <task:executor id="regulatoryExc" pool-size="1"
        queue-capacity="5" rejection-policy="CALLER_RUNS" />
   <int:service-activator input-channel="ticketCacheChannel"
        output-channel="sourceTicketsSplitter" ref="ticketSerActivator"
        method="fetchDataFromDB">
        <int:poller fixed-rate="10" task-executor="ticketSourceExc" />
    </int:service-activator>

    <!-- I am getting List<Tickets> -->
    <int:splitter input-channel="sourceTicketsSplitter"
        output-channel="sourceTicketChannel">
        <int:request-handler-advice-chain>
            <ref bean="retrier" />
        </int:request-handler-advice-chain>
        <int:poller fixed-rate="10" />
    </int:splitter>

    <int:handler-retry-advice id="retrier" max-attempts="4" recovery-channel="myErrorChannel" >
     <int:exponential-back-off initial="1000" multiplier="5" maximum="6000"/>
    </int:handler-retry-advice>

    <int:bridge id="regulatoryBrigde" input-channel="sourceTicketChannel"
        output-channel="regulatoryChannel">
        <int:poller fixed-rate="10" task-executor="regulatoryExc" />
    </int:bridge>

    <int:chain id="regulatoryChainFlow" input-channel="regulatoryChannel">
        <int:service-activator ref="regulatoryTaskActivator1"
            method="process" />
        <int:service-activator ref="regulatoryTaskActivator2"
            method="process" />
        <int:service-activator ref="regulatoryTaskActivator3"
            method="process" />
    </int:chain>

我已为拆分器配置重试策略。输出通道是深度为1(用于测试目的)的队列通道。我的期望是当我得到一个包含10个项目的列表时,应在队列已满后转到异常通道。这不是这种情况。我将线程睡眠置于RegulatoryTaskActivator1中以阻止队列

1 个答案:

答案 0 :(得分:1)

这是正确的,因为建议中不包含发送到输出通道的信息。这仅用于 request 部分。请仔细阅读有关此问题的文档:https://docs.spring.io/spring-integration/docs/5.0.8.RELEASE/reference/html/messaging-endpoints-chapter.html#message-handler-advice-chain。该建议仅适用于handleRequestMessage()方法。

更新

对于用例,当您想处理队列的有限大小并通过重试进行一些错误处理时,建议您将拆分结果输出到service-activator周围,@MessagingGateway error-channel方法上适当的@Retryable和可能的@Gateway

<splitter input-channel="sourceTicketsSplitter"
    output-channel="gatewayInputChannel">
       <poller fixed-rate="10" />
</splitter>

<service-activator input-channel="gatewayInputChannel" ref="gateway">
   <request-handler-advice-chain>
        <ref bean="retrier" />
    </request-handler-advice-chain>  
</service-activator>

<gateway id="gateway" default-request-channel="sourceTicketChannel"/>

如果您的流程是单向,并且您不希望收到regulatoryChainFlow的任何答复,那么默认的RequestReplyExchanger不符合您的要求,您需要通过void方法为网关引入一个简单的接口,并将该<gateway>配置为service-interface

更新

我为您忘记提及的是,需要使用timeout来发送到受限队列。如果没有这样的超时时间,发件人只需就座并等待房间,房间就会出现在上述Thread.sleep(10000);之后。

所以,您需要的是这样的

<int:gateway id="stateGateWay" default-request-channel="stateChannel" 
    default-request-timeout="100"
    service-interface="com.biswo.myspringapp.gateway.StateGateWay" />

请注意:

 <xsd:attribute name="default-request-timeout" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation>
                        <![CDATA[
                Provides the amount of time dispatcher would wait to send a message.
                This timeout would only apply if there is a potential to block in the send call.
                For example if this gateway is hooked up to a Queue channel. 
                Value is specified in milliseconds; it can be a simple long value or a SpEL
                expression; array variable #args is available.
                        ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>

此后,我开始在日志中看到关联,然后是Dispatcher has no subscribers

2018-10-09 14:53:03.466 TRACE 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : RetryContext retrieved: [RetryContext: count=0, lastException=null, exhausted=false]
2018-10-09 14:53:03.466 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Retry: count=0
2018-10-09 14:53:03.568 DEBUG 15808 --- [ask-scheduler-3] o.s.r.backoff.ExponentialBackOffPolicy   : Sleeping for 100
2018-10-09 14:53:03.669 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=1
2018-10-09 14:53:03.669 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Retry: count=1
2018-10-09 14:53:03.771 DEBUG 15808 --- [ask-scheduler-3] o.s.r.backoff.ExponentialBackOffPolicy   : Sleeping for 500
2018-10-09 14:53:04.271 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=2
2018-10-09 14:53:04.271 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Retry: count=2
2018-10-09 14:53:04.372 DEBUG 15808 --- [ask-scheduler-3] o.s.r.backoff.ExponentialBackOffPolicy   : Sleeping for 600
2018-10-09 14:53:04.973 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=3
2018-10-09 14:53:04.973 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Retry: count=3
2018-10-09 14:53:05.073 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=4
2018-10-09 14:53:05.073 DEBUG 15808 --- [ask-scheduler-3] o.s.retry.support.RetryTemplate          : Retry failed last attempt: count=4
2018-10-09 14:53:05.077  WARN 15808 --- [ask-scheduler-3] o.s.i.c.MessagePublishingErrorHandler    : Error message was not delivered.

org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.errorChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=ErrorMessage [payload=org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.errorChannel'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=ErrorMessage [payload=org.springframework.messaging.MessageHandlingException: nested exception is org.springframework.messaging.MessageDeliveryException: Failed to send message to channel 'stateChannel' within timeout: 100, failedMessage=GenericMessage [payload=State [id=2426, name=Pamanzi, countryId=141], headers={id=710d13df-dfbb-ba95-8d28-4785d1a1e3d3, timestamp=1539111184973}], failedMessage=GenericMessage [payload=State [id=2426, name=Pamanzi, countryId=141], headers={COUNTRY_ID=141, sequenceNumber=2, COUNTRY=com.biswo.myspringapp.model.Country@5fd4ea2d, sequenceSize=2, correlationId=ab423aa4-c80e-6af0-33a8-f57337f25352, id=a70d6b11-fc23-edd9-7973-1342c3fab8a6, timestamp=1539111183466}], headers={id=ee0ffd29-8e6a-ab5a-6ffb-1016fa38457e, timestamp=1539111185074}], failedMessage=ErrorMessage [payload=org.springframework.messaging.MessageHandlingException: nested exception is org.springframework.messaging.MessageDeliveryException: Failed to send message to channel 'stateChannel' within timeout: 100, failedMessage=GenericMessage [payload=State [id=2426, name=Pamanzi, countryId=141], headers={id=710d13df-dfbb-ba95-8d28-4785d1a1e3d3, timestamp=1539111184973}], failedMessage=GenericMessage [payload=State [id=2426, name=Pamanzi, countryId=141], headers={COUNTRY_ID=141, sequenceNumber=2, COUNTRY=com.biswo.myspringapp.model.Country@5fd4ea2d, sequenceSize=2, correlationId=ab423aa4-c80e-6af0-33a8-f57337f25352, id=a70d6b11-fc23-edd9-7973-1342c3fab8a6, timestamp=1539111183466}], headers={id=ee0ffd29-8e6a-ab5a-6ffb-1016fa38457e, timestamp=1539111185074}], headers={id=34d0e6e6-0af8-1078-5dd7-aa6643ba6c8d, timestamp=1539111185075}] for original GenericMessage [payload=[State [id=2425, name=Mayotte, countryId=141], State [id=2426, name=Pamanzi, countryId=141]], headers={COUNTRY_ID=141, id=ab423aa4-c80e-6af0-33a8-f57337f25352, COUNTRY=com.biswo.myspringapp.model.Country@5fd4ea2d, timestamp=1539111183462}]

仅仅是因为您的errorChannelDirectChannel,并且没有任何消费者。