我目前在处理Spring Cloud Streams(Elmhurst.RELEASE)中的消息处理期间抛出的异常时遇到问题。当我的应用程序在主处理方法中抛出异常时:
@SpringBootApplication
@EnableBinding(Processor.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@StreamListener(Processor.INPUT)
@SendTo(Processor.OUTPUT)
public String process(String message) {
externalService();
return message.toUpperCase();
}
private void externalService() {
throw new RuntimeException("An external call failed");
}
}
我似乎完全无法在任何错误通道上捕获此异常。通过阅读文档,我预计我将能够在全局" errorChannel"上接收ErrorMessage。或者在特定的" input.myGroup.errors"信道。
我试图使用Spring Integrations监听器:
@ServiceActivator(inputChannel="errorChannel")
public ErrorMessage onError(ErrorMessage message) {
return message;
}
与Spring Cloud Streams听众一样:
@StreamListener("errorChannel")
public ErrorMessage onError(ErrorMessage message) {
return message;
}
没有成功。我还使用了各种配置设置组合,例如" errorChannelEnabled:true"," max-retries:1"等等,对我能够捕捉到的错误没有任何影响我的处理器(使用调试点"返回消息"检查)。在配置" bindings.error.destination:myErrorTopic"时,我甚至不会在主题中收到任何错误消息。正如SCS文件中所建议的那样。
唯一似乎可行的是" enableDlq:true"在绑定配置级别。然而,这不能满足能够确定原始异常的重要需求,因为发布到DLQ的内容仅具有带有完整堆栈跟踪的标头。我不想解析堆栈跟踪来找出原始异常的类型或消息。
我应该采取更好的方法吗?还是我犯了一些愚蠢的错误?我的总体目标是将带有实际异常类型和异常消息的异常消息发送到DLQ。
当然,我可以在每个Processor / Source / Sink方法的周围放置try / catch语句,然后手动路由到不同的绑定通道,但这在很大程度上损害了SCS框架的价值主张。 / p>
我发现this example自定义DLQ处理是this早期StackOverflow问题的一部分,这似乎符合我的需求。然而,即使在将配置迁移到更新的SCS之后,这似乎与SCS Elmhurst / 2.0和Spring Kafka绑定器完全不兼容。
编辑我添加了一个Github repository来重现我的错误,因为复制相同的核心代码与Gary的回答似乎不起作用。我开始怀疑它是否是POM依赖,配置或Kafka活页夹问题。这个repo使用与Gary的答案相同的核心代码,因为我认为看到问题和调试有点简单。
GARY'答案之后的编辑我已经接受了Gary的回答,因为它解决了我原来的问题(在配置中有绑定环境时解决当前的框架问题) 。然而,DLQ消息最终对我的情况毫无帮助。我最终订阅了" errorChannel"一旦我根据Gary的回答得到了这个工作,并从那里创建了一个自定义错误消息,我发送到正常绑定的SCS频道。
答案 0 :(得分:1)
为什么你有return message;
?你期待它去哪儿?
这对我来说很好......
@SpringBootApplication
@EnableBinding(Sink.class)
public class So50506586Application {
public static void main(String[] args) {
SpringApplication.run(So50506586Application.class, args);
}
@StreamListener(Sink.INPUT)
public void listen(byte[] in) {
throw new RuntimeException("fail");
}
@ServiceActivator(inputChannel = "errorChannel")
public void errors(ErrorMessage em) {
System.out.println(em);
}
}
ErrorMessage [payload = org.springframework.messaging.MessagingException:调用com.example.So50506586Application#listen [1 args]时抛出异常;嵌套异常是java.lang.RuntimeException:fail,failedMessage = GenericMessage [payload = byte [3],headers = {kafka_offset = 0,...
...
引起:java.lang.RuntimeException:失败
...
修改强>
使用多个活页夹支持时(通过environment
内容)是一个错误。全局错误通道不可见。
这有效......
spring:
cloud:
stream:
bindings:
input:
destination: input
group: myGroup7
binder: kafka
# error:
# destination: errors
kafka.bindings.input.consumer.autoCommitOnError: true
kafka:
binder:
brokers: localhost:9092
(您不再需要使用Elmhurst的zkNodes)。
此外,您不应该使用遗留error.destination
内容,因为发送到错误频道的消息现在是一个包含大量信息的丰富ErrorMessage
对象,请使用dlq内容自动发布一个主题。
我们需要删除这些遗留错误目标属性。
这不起作用......
@ServiceActivator(inputChannel = "input.myGroup.errors")
public void errors(ErrorMessage em) {
System.out.println(em);
}
...因为服务激活器在绑定的不同应用程序上下文中。
目前,唯一的解决方法是不使用environment
样式的配置。如果您需要多个活页夹支持,我将无法为您提供解决方案。