Spring boot 春季卡夫卡-手动确认
我有一个spring引导应用程序,它监听Kafka流,并将记录发送给某个服务进行进一步处理。服务有时可能会失败。评论中提到了例外情况。到目前为止,我自己模拟了服务成功和异常场景 侦听器代码:Spring boot 春季卡夫卡-手动确认,spring-boot,apache-kafka,spring-kafka,Spring Boot,Apache Kafka,Spring Kafka,我有一个spring引导应用程序,它监听Kafka流,并将记录发送给某个服务进行进一步处理。服务有时可能会失败。评论中提到了例外情况。到目前为止,我自己模拟了服务成功和异常场景 侦听器代码: @Autowired PlanitService service @KafkaListener( topics = "${app.topic}", groupId = "notifGrp", containerFactory = "storeKafkaLi
@Autowired
PlanitService service
@KafkaListener(
topics = "${app.topic}",
groupId = "notifGrp",
containerFactory = "storeKafkaListener")
public void processStoreNotify(StoreNotify store) throws RefrigAlarmNotifyException{
service.planitStoreNotification(store);
// Some other logic which throws custom exception
// RefrigAlarmNotifyException
}
}
消费者工厂配置如下所示:
@Bean
public ConsumerFactory<String, StoreNotify> storeConsumerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getConsumerBootstrapServers());
config.put(ConsumerConfig.GROUP_ID_CONFIG, "notifGrp");
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
try (ErrorHandlingDeserializer2<String> headerErrorHandlingDeserializer = new ErrorHandlingDeserializer2<>(
new StringDeserializer());
ErrorHandlingDeserializer2<StoreNotify> errorHandlingDeserializer = new ErrorHandlingDeserializer2<>(
new JsonDeserializer<>(StoreNotify.class, objectMapper()))) {
return new DefaultKafkaConsumerFactory<>(config, headerErrorHandlingDeserializer,
errorHandlingDeserializer);
}
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, StoreNotify> storeKafkaListener() {
ConcurrentKafkaListenerContainerFactory<String, StoreNotify> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(storeConsumerFactory());
factory.getContainerProperties().setAckOnError(false);
factory.getContainerProperties().setAckMode(AckMode.RECORD);
//factory.setMessageConverter(new ByteArrayJsonMessageConverter());
DeadLetterPublishingRecoverer recoverer = new DeadLetterPublishingRecoverer(kafkaTemplate,
(r, e) -> {
LOGGER.error("Exception is of type: ", e);
if (e instanceof RestClientException) {
LOGGER.error("RestClientException while processing {} ", r.value(), e);
return new TopicPartition(storeDeadLtrTopic, r.partition());
}
else {
LOGGER.error("Generic exception while processing {} ", r.value(), e);
return new TopicPartition(storeErrorTopic, r.partition());
}
});
factory.setErrorHandler(new SeekToCurrentErrorHandler(recoverer, new FixedBackOff(0L, 0L)));
return factory;
}
对于这个用例,您不需要使用手动确认;只需配置一个
SeekToCurrentErrorHandler
,并向容器抛出异常;它将丢弃未处理的记录,执行查找并重新传递失败的消息
看
您可以使用死信发布恢复程序配置错误处理程序,该程序可用于在多次重试后将记录发送到死信主题
您可以配置哪些异常是可重试的
} catch (Exception exception) {
LOGGER.error("Exception while calling the service ", exception);
// Ignore the record
}
您不能像那样“吃”异常,让它传播到容器中
使用手动确认时,您必须添加确认
作为参数并进行确认。谢谢您提供的信息。我将采用这种方法。你知道为什么现有的代码不起作用吗。在上面的代码中,我忘了将确认作为一个参数,但在实际代码中它就在那里。因为您正在捕获异常,所以容器对此一无所知。即使您抛出了异常,默认错误处理程序也会记录异常并继续。是的,这很有意义。请参阅。如果添加SeekToCurrentErrorHandler
,则可以配置1)根据异常类型重试多少次,以及2)在进行下一次传递尝试之前延迟多长时间。这允许您控制哪些异常是致命的,不应重试。默认情况下,有10次无回退的交付尝试。默认情况下,某些异常被认为是致命的。同样,请参阅参考手册。重试时,您可以记录或发送到另一个主题。顶级异常是ListenerExecutionFailedException
您需要if(e.getCause()instanceof RestClientException){
} catch (Exception exception) {
LOGGER.error("Exception while calling the service ", exception);
// Ignore the record
}