如何在弹簧集成中为<int:gateway>添加断路器

时间:2015-12-31 17:34:47

标签: spring spring-integration

这是我的代码,我在spring-config.xml中定义了一个网关,如下面的

<int:gateway id="myGateway"
                 service-interface="com.sample.si.MyService"
                 error-channel="myError-channel"
                 default-request-channel="sendServiceChannel" 
                 >
        <int:method name="sendService" request-channel="sendServiceChannel" /       

当我调试我的测试时,它直接转到RequesthandlerCircuitBreakerAdvice.class并且永远不会进入我的错误通道,下面是我的错误通道

<int:channel id="myError-channel">

</int:channel>

<int:chain input-channel="myError-channel">
    <int:service-activator ref="myErrorHandler" method="resolveError" />
</int:chain>

当我从网关遇到异常时,我想重定向到错误频道,并希望使用circuitbreaker halfopen timelimit将每条消息重定向到错误频道。任何帮助表示赞赏

编辑显示出站网关

<int-ws:outbound-gateway id="sendMyService"
                         uri="${my.gateway.send.uri}"
                         mapped-request-headers="*"
                         marshaller="SOAPMarshaller"
                         unmarshaller="SOAPMarshaller"
                         message-sender="soapMessageSender"
                         request-channel="sendServiceChannel"
                         fault-message-resolver="faultResolver"
                         reply-channel="sendServiceResponseChannel">


<int:request-handler-advice-chain>
        <bean class="org.springframework.integration.handler.advice.RequestHandlerCircuitBreakerAdvice">
            <property name="threshold" value="1" />
            <property name="halfOpenAfter" value="10000" />
        </bean>
    </int:request-handler-advice-chain>

我希望断路器之间的断路器,以便当出站网关中提供的uri不可用时我不想点击出站网关,感谢您查看Gary Russell

这是我的测试用例

public class EmailGatewayProducerConsumerTest {

@Inject
@Qualifier("myGateway")
private Myservice myService;

@Test
public void senderTest(){
MyRequest myRequest = new MyRequest(12,"rajendra","rajednra.ch@hotmail.com");
           try {
        myService.sendService(myRequest);
    }catch (Exception e){
        //System.out.println("Caught Exception " +e);
    }
}

}

错误处理程序是将异常消息发送到队列并将其读回并再次发送到网关这是我的错误处理程序代码

public class ErrorHandler{@Inject private JmsTemplate jmsTemplate;
     public void resolveError( Message<MessagingException> message) {
         try{ 
             MyRequest myRequest=(MessageRequest)message.getPayload().getFailedMessage().getPayload()
             jmsTemplate.convertAndSend(DATA_QUEUE, myRequest);
        } catch(Exception e){
    //log error
        } 
    }
}

这是我的消费者使用它并发送回网关

 @JmsListener(destination = DATA_QUEUE)public void consume(MyRequest myRequest) throws InterruptedException {
log.info("Receiving  event: {}", myRequest);
try {
   myService.sendService(myRequest)
}catch (Exception e){
    log.error(e.toString());
} }

例外:

Caused by: org.springframework.ws.client.WebServiceIOException: I/O error: Connect to localhost:10002 timed out; nested exception is org.apache.http.conn.ConnectTimeoutException: Connect to localhost:10002 timed out
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:561)
at org.springframework.integration.ws.MarshallingWebServiceOutboundGateway.doHandle(MarshallingWebServiceOutboundGateway.java:81)
at org.springframework.integration.ws.AbstractWebServiceOutboundGateway.handleRequestMessage(AbstractWebServiceOutboundGateway.java:188)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler$AdvisedRequestHandler.handleRequestMessage(AbstractReplyProducingMessageHandler.java:144)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice$1.execute(AbstractRequestHandlerAdvice.java:74)
at org.springframework.integration.handler.advice.RequestHandlerCircuitBreakerAdvice.doInvoke(RequestHandlerCircuitBreakerAdvice.java:61)
at org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice.invoke(AbstractRequestHandlerAdvice.java:69)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy102.handleRequestMessage(Unknown Source)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.doInvokeAdvisedRequestHandler(AbstractReplyProducingMessageHandler.java:117)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:102)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
... 90 more

2 个答案:

答案 0 :(得分:0)

网关(以及错误通道)位于断路器的下游 - 您需要显示服务激活器的上游(之前) - 您需要配置错误通道以处理断路器结果

也就是说,你在这里有一个循环依赖 - 网关正在发送给服务激活器,它再次调用网关。

您需要进一步解释您要做的事情 - 显示更多配置 - 上游和下游。

修改

请记住,这将导致无限循环,因为失败的消息将无限期地重试。

与此测试用例相比,发送到JMS不应该有任何不同,这完全符合我的预期(包括无限循环)......

public interface GW {

    void send(String foo);

}


<int:gateway id="gw" service-interface="com.example.GW" default-request-channel="foo"
    error-channel="errorChannel"/>

<int:service-activator input-channel="foo" expression = "1 / 0"> <!-- always fail -->
    <int:request-handler-advice-chain>
        <bean class="org.springframework.integration.handler.advice.RequestHandlerCircuitBreakerAdvice">
            <property name="threshold" value="1" />
            <property name="halfOpenAfter" value="10000" />
        </bean>
    </int:request-handler-advice-chain>
</int:service-activator>

<int:bridge input-channel="errorChannel" output-channel="retryChannel" />

<int:channel id="retryChannel">
    <int:queue />
</int:channel>

<int:chain input-channel="retryChannel">
    <int:transformer expression="payload.failedMessage.payload" />
    <int:service-activator ref="gw" />
    <int:poller fixed-delay="1000" />
</int:chain>

结果:

org.springframework.messaging.MessageHandlingException: Expression evaluation failed: 1 / 0;
...
Caused by: java.lang.ArithmeticException: / by zero

CircuitBreakerOpenException: Circuit Breaker is Open for ServiceActivator for [ExpressionEvaluatingMessageProcessor for: [1 / 0]] 

CircuitBreakerOpenException: Circuit Breaker is Open for ServiceActivator for [ExpressionEvaluatingMessageProcessor for: [1 / 0]] 

CircuitBreakerOpenException: Circuit Breaker is Open for ServiceActivator for [ExpressionEvaluatingMessageProcessor for: [1 / 0]] 

答案 1 :(得分:0)

上面是我编辑的配置,对我来说实现了断路器,经过所有的更改后我仍然遇到了这个问题的半开时间,我增加到 60000 并且它在上面的解决方案中工作了这个问题应该适用于断路器,请遵循我和Gary Russell的评论。