Spring integration 在Spring Intehration中读取Aws Kinesis流时,全局处理特定于通道的错误

Spring integration 在Spring Intehration中读取Aws Kinesis流时,全局处理特定于通道的错误,spring-integration,spring-cloud,amazon-kinesis,spring-integration-aws,Spring Integration,Spring Cloud,Amazon Kinesis,Spring Integration Aws,我正在收听aws kinesis流,并启用了全局和特定于通道的错误处理,如下所示 应用程序Yml server: port: 8090 eureka.client.enabled: false spring: cloud: stream: bindings: MyInboundChannel: group: myGroup destination: awsstream co

我正在收听aws kinesis流,并启用了全局和特定于通道的错误处理,如下所示

应用程序Yml

server:
  port: 8090

eureka.client.enabled: false

spring:
  cloud:
    stream:
      bindings:        
        MyInboundChannel:
          group: myGroup
          destination: awsstream
          content-type: application/json
          errorChannelEnabled: true
          errors:
            destination: myGrouperrorChannel


cloud:
  aws:
    region:
      static: us-east-1
    credentials:
      accessKey: accessKey
      secretKey: secretKey
    kinesis:
      endpoint: endpoint
我已经为全局错误通道编写了如下处理程序

错误处理程序

public class ErrorHandler {

  @ServiceActivator(inputChannel = "errorChannel")
  public void errorChannel(Throwable message) {
    log.error("error has been reported " + message);
  }

}
我的通道特定错误通道的配置

  @Bean(name = "myGrouperrorChannel")
  public MessageChannel myGrouperrorChannel() {
    return new DirectChannel();
  }
消息侦听器和通道错误列表器

@EnableBinding(Binder.class)
public class MessageListener {

  @StreamListener("MyInboundChannel") 
  public void receiveMessage(String message) {
    System.out.println("MyInboundChannel" + message);
    //throw exception explicitly
    throw new RuntimeException("Iris error");
  }


    @StreamListener("myGrouperrorChannel")
  public void myGrouperrorChannel(Message message) {
    log.error("myGrouperrorChannel has been reported " + message);
  }

}
粘结剂界面

public interface Binder {

  @Input("MyInboundChannel")
  SubscribableChannel itemMessage();

}
该错误既不由全局错误通道处理,也不由我的通道特定的错误通道处理

  @Bean(name = "myGrouperrorChannel")
  public MessageChannel myGrouperrorChannel() {
    return new DirectChannel();
  }
我错过了什么吗

异常日志

Exception in thread "-kinesis-consumer-1" org.springframework.messaging.MessagingException: Exception thrown while invoking com.package.MessageListener  #receiveMessage[1 args]; nested exception is java.lang.RuntimeException: my error, failedMessage=GenericMessage [payload={hello
}, headers={aws_partitionKey=partitionKey-0, aws_shard=shardId-000000000000, aws_sequenceNumber=99579810409965332842672442827229165777883733894461652994, id=12d9f4a8-b5d2-2252-647f-b28bad087f5c, contentType=application/json, aws_stream=awsstream, timestamp=1519149049433}]
    at org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:63)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
    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:425)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:375)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:360)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:271)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:188)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:70)
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:64)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
    at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:188)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter.access$5100(KinesisMessageDrivenChannelAdapter.java:82)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ShardConsumer.processRecords(KinesisMessageDrivenChannelAdapter.java:912)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ShardConsumer.access$3600(KinesisMessageDrivenChannelAdapter.java:688)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ShardConsumer$2.run(KinesisMessageDrivenChannelAdapter.java:822)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ConsumerInvoker.run(KinesisMessageDrivenChannelAdapter.java:1003)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: my error
    at com.package.MessageListener.receiveMessage(MessageListener.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:180)
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:112)
    at org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:55)
    ... 30 more
有人能帮忙吗

更新 我已尝试使用以下代码,但无法捕获错误。我尝试了流侦听器和服务激活器。如果我做错了什么事,你能帮帮我吗

应用程序Yml

    server.port: 8082

    spring:
      cloud:
        stream:
          bindings:
            output:
              destination: awsstream.myprocessor
              content-type: application/json
              producer:
                partitionKeyExpression: "1"
            input: 
              group: grp
              destination: awsstream.mysource
              content-type: application/json
              errorChannelEnabled: true
            input2:
              group: grp2
              destination: awsstream.mysink
              content-type: application/json
阶级

任何地方都不会发现错误

Exception in thread "-kinesis-consumer-1" org.springframework.messaging.MessagingException: Exception thrown while invoking com.company.cloud.MyApplication#transform[1 args]; nested exception is java.lang.IllegalStateException: Invalid payload: aasa, failedMessage=GenericMessage [payload=aasa, headers={aws_partitionKey=partitionKey-0, aws_shard=shardId-000000000000, aws_sequenceNumber=49579810409608520919496497856488469248195805892912873474, id=2595d37f-82e1-b6bd-beed-3a9a3bb7243e, contentType=application/json, aws_stream=awsstream.mysource, timestamp=1520087287991}]
    at org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:63)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
    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:425)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:375)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:360)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:271)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:188)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:70)
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:64)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
    at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:188)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter.access$5100(KinesisMessageDrivenChannelAdapter.java:82)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ShardConsumer.processRecords(KinesisMessageDrivenChannelAdapter.java:912)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ShardConsumer.access$3600(KinesisMessageDrivenChannelAdapter.java:688)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ShardConsumer$2.run(KinesisMessageDrivenChannelAdapter.java:822)
    at org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter$ConsumerInvoker.run(KinesisMessageDrivenChannelAdapter.java:1003)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Invalid payload: aasa
    at com.company.cloud.MyApplication.transform(MyApplication.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:180)
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:112)
    at org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:55)

你知道它是按设计工作的。只是问题不那么明显

我刚刚推动了项目的集成测试

您可以在
KinesisBinderProcessorTests
中找到它

但总的想法是这样的:

@RunWith(SpringRunner.class)
@SpringBootTest(
        webEnvironment = SpringBootTest.WebEnvironment.NONE,
        properties = "spring.cloud.stream.bindings.input.group = " + KinesisBinderProcessorTests.CONSUMER_GROUP)
@DirtiesContext
public class KinesisBinderProcessorTests {

    static final String CONSUMER_GROUP = "testGroup";

...
    @EnableBinding(Processor.class)
    public static class ProcessorConfiguration {

        @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
        public String transform(Message<String> message) {
            String payload = message.getPayload();
            if (!"junk".equals(payload)) {
                return payload.toUpperCase();
            }
            else {
                throw new IllegalStateException("Invalid payload: " + payload);
            }
        }

        @Bean(name = Processor.INPUT + "." + CONSUMER_GROUP + ".errors")
        public SubscribableChannel consumerErrorChannel() {
            return new PublishSubscribeChannel();
        }
@RunWith(SpringRunner.class)
@春靴测试(
webEnvironment=SpringBootTest.webEnvironment.NONE,
properties=“spring.cloud.stream.bindings.input.group=“+KinesisBinderProcessorTests.CONSUMER\u组)
@肮脏的环境
公共类KinesisBinderProcessorTests{
静态最终字符串使用者\ u GROUP=“testGroup”;
...
@EnableBinding(Processor.class)
公共静态类处理器配置{
@转换器(inputChannel=Processor.INPUT,outputChannel=Processor.OUTPUT)
公共字符串转换(消息){
字符串有效载荷=message.getPayload();
如果(!“垃圾”。等于(有效载荷)){
返回有效负载.toUpperCase();
}
否则{
抛出新的IllegalStateException(“无效负载:+负载”);
}
}
@Bean(name=Processor.INPUT+“+CONSUMER\u GROUP+”.errors)
公共订阅频道ConsumerRorChannel(){
返回新的PublishSubscribeChannel();
}
请注意
属性以及如何使用该属性声明
consumerErrorChannel

因此,使用
@StreamListener(“myGrouperrorChannel”)
而不是
@StreamListener(“MyInboundChannel.myGroup.errors”)
所需的是错误的


我还检查了测试中消费者的错误是否被发送到全局
错误频道
。不确定那里发生了什么事…

您知道它是按设计工作的。只是问题不是很明显

我刚刚推动了项目的集成测试

您可以在
KinesisBinderProcessorTests
中找到它

但总的想法是这样的:

@RunWith(SpringRunner.class)
@SpringBootTest(
        webEnvironment = SpringBootTest.WebEnvironment.NONE,
        properties = "spring.cloud.stream.bindings.input.group = " + KinesisBinderProcessorTests.CONSUMER_GROUP)
@DirtiesContext
public class KinesisBinderProcessorTests {

    static final String CONSUMER_GROUP = "testGroup";

...
    @EnableBinding(Processor.class)
    public static class ProcessorConfiguration {

        @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
        public String transform(Message<String> message) {
            String payload = message.getPayload();
            if (!"junk".equals(payload)) {
                return payload.toUpperCase();
            }
            else {
                throw new IllegalStateException("Invalid payload: " + payload);
            }
        }

        @Bean(name = Processor.INPUT + "." + CONSUMER_GROUP + ".errors")
        public SubscribableChannel consumerErrorChannel() {
            return new PublishSubscribeChannel();
        }
@RunWith(SpringRunner.class)
@春靴测试(
webEnvironment=SpringBootTest.webEnvironment.NONE,
properties=“spring.cloud.stream.bindings.input.group=“+KinesisBinderProcessorTests.CONSUMER\u组)
@肮脏的环境
公共类KinesisBinderProcessorTests{
静态最终字符串使用者\ u GROUP=“testGroup”;
...
@EnableBinding(Processor.class)
公共静态类处理器配置{
@转换器(inputChannel=Processor.INPUT,outputChannel=Processor.OUTPUT)
公共字符串转换(消息){
字符串有效载荷=message.getPayload();
如果(!“垃圾”。等于(有效载荷)){
返回有效负载.toUpperCase();
}
否则{
抛出新的IllegalStateException(“无效负载:+负载”);
}
}
@Bean(name=Processor.INPUT+“+CONSUMER\u GROUP+”.errors)
公共订阅频道ConsumerRorChannel(){
返回新的PublishSubscribeChannel();
}
请注意
属性以及如何使用该属性声明
consumerErrorChannel

因此,使用
@StreamListener(“myGrouperrorChannel”)
而不是
@StreamListener(“MyInboundChannel.myGroup.errors”)
所需的是错误的


我还在测试中检查消费者的错误是否被发送到全局
errorChannel
。不确定那里发生了什么…

我们至少可以有异常的日志吗?我希望看到一个调用堆栈来确定罪魁祸首,如果是这样的话one@ArtemBilan感谢您的关注。我故意将RuntimeException抛出m listener和添加的日志。您可以look@ArtemBilan如果您有任何建议,请提供。我将于明天与@GaryRussell就此进行讨论。不确定发生了什么事
errorChannelEnabled
生产者的属性。消费者方面有错误。我们至少可以有例外情况的日志吗?我想看看调用stack来确定罪魁祸首,如果one@ArtemBilan感谢您的关注。我故意从侦听器中抛出RuntimeException并添加了日志。您能帮我看一下吗look@ArtemBilan如果您有任何建议,请提供。我明天将与@GaryRussell就此进行讨论。不确定发生了什么事
errorChannelEnabled
producer
属性。在消费者方面它是错误的。非常感谢。我将尝试此操作并更新您可以在全局
errorChannel
(所有输入)或特定输入
myInboundChannel.myGroup.errors上添加
@ServiceActivator
(或任何订户)(除非Kinesis活页夹对其进行了自定义。每个单独的错误频道都是一个发布/子频道,桥接到全局
errorChannel
。有效负载是
ErrorMessage
,因此是