我的用例是接收Kafka消息,多次尝试进行一次休息呼叫,并在用尽后将失败的消息转储到Kafka DLQ主题上。
@StreamListener(EventSource.SOME_CHANNEL)
public void processMessage(Message<?> unsolicitedMessage) {
String aString = .....
oneService.act(aString);
}
@Retryable
在多次尝试的处理逻辑方面运行良好。
@Retryable(value = {OneException.class, TwoException}, maxAttempts = 3,
backoff = @Backoff(delay = 1000))
public boolean act(String message, String endPoint) {
//do stuff
}
要使Spring Cloud Stream内置的Kafka DLQ发布开始(enableDlq: true
),则需要将异常冒泡到@StreamListener
注释的方法中,以使Kafka活页夹能够执行必要的操作。
但是,这样做时,我无法利用带有注释的@Recover
方法,该方法在重试后将流完美地放置在 :
@Recover
public boolean recoverOnToDLQ(OneException ex, String message, String
endPoint) {
throw ex; //Required for StreamListener Kafka DLQ to kick in!
}
问题:是否有一种方法可以从@Recover
方法中触发Kakfa DLQ发布而无需重新引发异常?
因为我仅将其用于重新抛出,所以我相信我不会有效利用其中获得的更严格的控制。这还将简化单元测试用例,并更好地捕获代码级的逻辑吗?关于如何更好地处理此问题,是否有任何想法?
到目前为止,我正在使用spring-cloud,spring-cloud-stream和spring-retry的所有最新版本。
答案 0 :(得分:1)
可以做到,但是问题是“你为什么想要?”。
活页夹已重试内置;只需将异常扔回给活页夹,重试用尽后它将把数据发送到DLQ。使用活页夹使用者重试属性配置重试。您不需要一行其他代码。
通过使用RetryTemplate
,您将嵌套2个maxAttempts
(除非您通过将使用者ErrorMessage
属性设置为1来禁用活页夹重试)。
当然,您可以配置自己的DLQ目标,只需在恢复器中写入所需内容即可。但是,要使用活页夹的内置DLQ发布者,您必须制作一个特殊的ConsumerRecord
(具有发布者所需的属性)并将其发送到绑定的错误通道。发布者需要原始的kafka RetryTemplate @Bean
,您必须重新创建它们,因为监听者无法使用。
所有方面,对于您的用例,仅使用活页夹的重试配置似乎要简单得多。
编辑
在2.0.x中,您可以向应用程序中添加一个@StreamRetryTemplate
,它将用于所有使用者绑定(覆盖绑定属性)。
可以使用任何重试策略,可重试的异常等自定义此模板。
在2.0.2版本中,必须使用RetryTemplate
进行限定;之所以修复此问题,是因为任何 {{1}}会覆盖属性,而这可能不是您想要的行为。