【问题标题】:Why Spring Integration failover doesn't show exception为什么 Spring Integration 故障转移不显示异常
【发布时间】:2017-05-10 04:19:08
【问题描述】:

我对 Spring Integration 调度程序的故障转移有一些问题,如果我的消息处理程序失败,应该会显示异常。

我有简单的 Spring 集成上下文:

<int:gateway default-request-channel="inboundChannel"
             service-interface="com.some.gateway.PrinterGateway"/>

    <int:channel id="inboundChannel">
        <int:dispatcher failover="false"/>
    </int:channel>

    <!--first Message Handler (broken)-->    
    <bean id="printService" class="com.some.service.PrinterService"/>

    <int:service-activator input-channel="inboundChannel"
                           method="print"
                           ref="printService"/>

    <!--second Message Handler-->
    <bean id="uppercasePrintService"
          class="com.some.service.UppercasePrinterService"/>

    <int:service-activator input-channel="inboundChannel"
                           method="printUppercase"
                           ref="uppercasePrintService"/>

还有我损坏的消息处理程序类:

public class PrinterService {

    public void print(Message<String> message) {
        throw new RuntimeException("This is error");
    }
}
  1. 您能解释一下为什么我的故障转移不起作用吗?
  2. 为什么会跳过 RuntimeException 并将消息传递到下一个处理程序?

【问题讨论】:

    标签: java spring spring-boot spring-integration failover


    【解决方案1】:

    对我来说很好用。

    尚不清楚您要达到的目标;也许你误解了负载平衡?

    默认情况下,负载均衡策略是轮询,这意味着第一条消息将到达失败的端点;第二个将进入良好的端点。 消息将交替显示。

    19:23:16.867 [main] DEBUG org.springframework.integration.channel.DirectChannel - preSend on channel 'org.springframework.integration.channel.DirectChannel@1794d431', message: GenericMessage [payload=foo, headers={id=9c3b1493-0a9a-e324-6da3-262079677ed0, timestamp=1494199396867}]
    org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'null'; nested exception is java.lang.RuntimeException: foo, failedMessage=GenericMessage [payload=foo, headers={id=9c3b1493-0a9a-e324-6da3-262079677ed0, timestamp=1494199396867}]
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:449)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
        at com.example.So43836561Application.main(So43836561Application.java:16)
    Caused by: java.lang.RuntimeException: foo
        at com.example.So43836561Application.lambda$0(So43836561Application.java:13)
        at com.example.So43836561Application$$Lambda$1/1121454968.handleMessage(Unknown Source)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:160)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
        at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
        ... 2 more
    19:23:18.875 [main] DEBUG org.springframework.integration.channel.DirectChannel - preSend on channel 'org.springframework.integration.channel.DirectChannel@1794d431', message: GenericMessage [payload=bar, headers={id=90aaa16c-a8c1-9162-ba8f-532fa3201c7f, timestamp=1494199398875}]
    Second Service: GenericMessage [payload=bar, headers={id=90aaa16c-a8c1-9162-ba8f-532fa3201c7f, timestamp=1494199398875}]
    19:23:18.876 [main] DEBUG org.springframework.integration.channel.DirectChannel - postSend (sent=true) on channel 'org.springframework.integration.channel.DirectChannel@1794d431', message: GenericMessage [payload=bar, headers={id=90aaa16c-a8c1-9162-ba8f-532fa3201c7f, timestamp=1494199398875}]
    

    如果您使用 NONE 负载平衡策略,所有消息都会发送到失败的消息。

    19:26:38.005 [main] DEBUG org.springframework.integration.channel.DirectChannel - preSend on channel 'org.springframework.integration.channel.DirectChannel@7d9d1a19', message: GenericMessage [payload=foo, headers={id=6a69efe9-dbbd-c79b-41a9-6964fd4c8ccc, timestamp=1494199598004}]
    org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'null'; nested exception is java.lang.RuntimeException: foo, failedMessage=GenericMessage [payload=foo, headers={id=6a69efe9-dbbd-c79b-41a9-6964fd4c8ccc, timestamp=1494199598004}]
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:449)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
        at com.example.So43836561Application.main(So43836561Application.java:16)
    Caused by: java.lang.RuntimeException: foo
        at com.example.So43836561Application.lambda$0(So43836561Application.java:13)
        at com.example.So43836561Application$$Lambda$1/2009787198.handleMessage(Unknown Source)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:160)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
        at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
        ... 2 more
    19:26:40.009 [main] DEBUG org.springframework.integration.channel.DirectChannel - preSend on channel 'org.springframework.integration.channel.DirectChannel@7d9d1a19', message: GenericMessage [payload=bar, headers={id=9428a10e-3a17-79d5-e4bd-731fc88ef0fe, timestamp=1494199600008}]
    Exception in thread "main" org.springframework.messaging.MessageDeliveryException: failed to send Message to channel 'null'; nested exception is java.lang.RuntimeException: foo, failedMessage=GenericMessage [payload=bar, headers={id=9428a10e-3a17-79d5-e4bd-731fc88ef0fe, timestamp=1494199600008}]
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:449)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
        at com.example.So43836561Application.main(So43836561Application.java:22)
    Caused by: java.lang.RuntimeException: foo
        at com.example.So43836561Application.lambda$0(So43836561Application.java:13)
        at com.example.So43836561Application$$Lambda$1/2009787198.handleMessage(Unknown Source)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:160)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
        at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
        ... 2 more
    

    如果这不是问题,也许您有第二个通道 bean,其 id 相同但配置不同?

    无论如何,打开org.springframework.integration 的调试日志记录会告诉你发生了什么。

    编辑

    由于您使用的是异步网关(返回 Future&lt;?&gt;),您需要检查结果以获取异常...

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        List<Future<Message<String>>> futures = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Message<String> message = MessageBuilder.withPayload("Some payload that created for message id: " + i)
                    .build();
            log.info("Sending message " + i);
            futures.add(gateway.print(message));
        }
        futures.forEach(f -> {
            try {
                System.out.println(f.get());
            }
            catch (ExecutionException e) {
                System.out.println(e.getCause().getMessage());
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
    }
    

    public String printUppercase(Message<String> message) {
        log.info(message.getPayload().toUpperCase());
        return message.getPayload().toUpperCase();
    }
    

    结果:

    This is error
    GenericMessage [payload=SOME PAYLOAD THAT CREATED FOR MESSAGE ID: 1, headers={id=229ad2ee-f424-61da-a9bc-a631de9bd5d0, timestamp=1494360966556}]
    GenericMessage [payload=SOME PAYLOAD THAT CREATED FOR MESSAGE ID: 2, headers={id=7e2c45c4-2c7b-f3f3-243d-56d9de33375f, timestamp=1494360966556}]
    This is error
    This is error
    This is error
    GenericMessage [payload=SOME PAYLOAD THAT CREATED FOR MESSAGE ID: 6, headers={id=79f4ef60-9dea-60f3-3972-a9eefde67ebf, timestamp=1494360966556}]
    GenericMessage [payload=SOME PAYLOAD THAT CREATED FOR MESSAGE ID: 7, headers={id=626d1347-e5bd-ec4c-b153-71174cc7f18d, timestamp=1494360966556}]
    This is error
    

    【讨论】:

    • 在禁用我的failover 后,我没有此堆栈跟踪。我想显示你附加的这个跟踪,但负载平衡行为看起来像启用了failover
    • 我听不懂你在说什么。正如我所说,根据您提供的信息,您所描述的内容是不可能的;图片中必须有其他东西。如果您可以在某个地方(github 或类似网站)发布一个完整的示例来展示您所看到的行为,那么有人将能够找出您做错了什么。
    • 当您使用异步网关时,您不会在调用线程上遇到异常 - 您需要检查 Future>。顺便说一句,如果某些流可能不返回结果,您应该在网关上将回复超时设置为 0 - 否则您将占用一个线程等待永远不会出现的结果。
    • 是的,这就是为什么我已经使用Future&lt;Message&lt;String&gt;&gt; 作为我的网关方法的返回类型。
    • 使用Future 对挂起的线程没有帮助——当结果(或异常到达)时,我们仍然需要一个线程来填充未来——下游流可能是异步的。如果您不期望结果,最好使用void 网关,或者将回复超时设置为 0。
    猜你喜欢
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多