Error handling 如何配置spring kafka以忽略错误格式的消息?

Error handling 如何配置spring kafka以忽略错误格式的消息?,error-handling,apache-kafka,spring-kafka,Error Handling,Apache Kafka,Spring Kafka,我们的卡夫卡主题之一存在问题,该主题被工厂使用的DefaultKafkanConsumerFactory&ConcurrentMessageListenerContainer组合使用。不幸的是,有人有点热情,在这个话题上发表了一些无效的信息。似乎spring kafka在处理完第一条消息后,都会悄无声息地失败。是否可以让spring kafka记录错误并继续?查看记录的错误消息,似乎ApacheKafka客户端库应该处理这样一种情况:当迭代一批消息时,其中一个或多个可能无法解析 以下代码是说明此

我们的卡夫卡主题之一存在问题,该主题被工厂使用的
DefaultKafkanConsumerFactory
&
ConcurrentMessageListenerContainer
组合使用。不幸的是,有人有点热情,在这个话题上发表了一些无效的信息。似乎spring kafka在处理完第一条消息后,都会悄无声息地失败。是否可以让spring kafka记录错误并继续?查看记录的错误消息,似乎ApacheKafka客户端库应该处理这样一种情况:当迭代一批消息时,其中一个或多个可能无法解析

以下代码是说明此问题的示例测试用例:

import org.apache.kafka.clients.consumer.ConsumerConfig;
导入org.apache.kafka.clients.consumer.ConsumerRecord;
导入org.apache.kafka.clients.producer.ProducerConfig;
导入org.apache.kafka.common.serialization.Serializer;
导入org.apache.kafka.common.serialization.StringDeserializer;
导入org.apache.kafka.common.serialization.StringSerializer;
导入org.junit.ClassRule;
导入org.junit.Test;
导入org.springframework.kafka.core.DefaultKafkaConsumerFactory;
导入org.springframework.kafka.core.DefaultKafkaProducerFactory;
导入org.springframework.kafka.core.KafkaTemplate;
导入org.springframework.kafka.listener.KafkaMessageListenerContainer;
导入org.springframework.kafka.listener.MessageListener;
导入org.springframework.kafka.listener.config.ContainerProperties;
导入org.springframework.kafka.support.SendResult;
导入org.springframework.kafka.support.serializer.JsonDeserializer;
导入org.springframework.kafka.support.serializer.JsonSerializer;
导入org.springframework.kafka.test.rule.kafkamebedded;
导入org.springframework.kafka.test.utils.ContainerTestUtils;
导入org.springframework.util.concurrent.ListenableFuture;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.Objects;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.LinkedBlockingQueue;
导入java.util.concurrent.TimeUnit;
导入java.util.concurrent.TimeoutException;
导入静态org.junit.Assert.assertEquals;
导入静态org.junit.Assert.assertThat;
导入静态org.springframework.kafka.test.hamcrest.KafkaMatchers.hasKey;
导入静态org.springframework.kafka.test.hamcrest.KafkaMatchers.hasValue;
/**
*@作者jfreedman
*/
公共类测试卡夫卡{
私有静态最终字符串TOPIC1=“spring.kafka.1.t”;
@阶级规则
公共静态卡夫卡嵌入卡夫卡=新卡夫卡嵌入(1,真,1,主题1);
@试验
public void submitMessageHengArbageTheNotherMessage()引发异常{
最终阻塞队列记录=createListener(TOPIC1);
最终KafkaTemplateObjectTemplate=createPublisher(“json”,新的JsonSerializer());
sendAndVerifyMessage(记录,对象模板,“foo”,新JsonObject(“foo”),0L);
//将一些无法封送的垃圾文本推送到Kafka,这不应中断处理
最终KafkaTemplate garbageTemplate=createPublisher(“垃圾”,新的StringSerializer());
final SendResult garbageResult=garbageTemplate.send(主题1,“bar”,“bar”).get(5,时间单位.秒);
assertEquals(1L,garbageResult.getRecordMetadata().offset());
发送和验证消息(记录,对象模板,“baz”,新JsonObject(“baz”),2L);
}
私有KafkaTemplate createPublisher(最终字符串标签,最终序列化程序序列化程序){
final-Map-producerProps=new-HashMap();
producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,embeddedKafka.getBrokersassString());
producerProps.put(ProducerConfig.CLIENT\u ID\u CONFIG,“TestPublisher-”+标签);
producerProps.put(ProducerConfig.ACKS_CONFIG,“all”);
producerProps.put(ProducerConfig.RETRIES\u CONFIG,2);
producerProps.put(ProducerConfig.MAX\u在飞行中请求每个连接,1);
producerProps.put(ProducerConfig.REQUEST\u TIMEOUT\u MS\u CONFIG,5000);
producerProps.put(ProducerConfig.MAX\u BLOCK\u MS\u CONFIG,5000);
producerProps.put(ProducerConfig.KEY\u SERIALIZER\u CLASS\u CONFIG,StringSerializer.CLASS);
producerProps.put(ProducerConfig.VALUE\u SERIALIZER\u CLASS\u CONFIG,SERIALIZER.getClass());
最终DefaultKafkaProducerFactory pf=新的DefaultKafkaProducerFactory(producerProps);
pf.setValueSerializer(序列化程序);
返回新的卡夫卡模板(pf);
}
private BlockingQueue createListener(最终字符串主题)引发异常{
final Map ConsumerOps=新HashMap();
consumerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,embeddedKafka.getBrokersassString());
consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG,“TestConsumer”);
put(ConsumerConfig.ENABLE\u AUTO\u COMMIT\u CONFIG,true);
put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG,“100”);
consumerProps.put(ConsumerConfig.SESSION\u TIMEOUT\u MS\u CONFIG,15000);
consumerProps.put(ConsumerConfig.KEY\u反序列化程序\u类\u配置,StringDeserializer.CLASS);
consumerProps.put(ConsumerConfig.VALUE\反序列化程序\类\配置,JsonDeserializer.CLASS);
最终DefaultKafkaConsumerFactory cf=新的DefaultKafkaConsumerFactory(ConsumerOps);
cf.setValueDeserializer(新的JsonDeserializer(JsonObject.class));
最终KafkCamessageListenerContainer容器=新KafkCamessageListenerContainer(参见新容器属性(主题));
final BlockingQueue记录=新建LinkedBlockingQueue();
container.setupMessageListener((MessageListener)记录::add);
container.setBeanName(“TestListener”);
container.start();
ContainerTestUtils.waitForAssignment(容器,embeddedKafka.getPartitionsPerTopic
@Bean
public ConsumerAwareListenerErrorHandler listen3ErrorHandler() {
    return (m, e, c) -> {
        this.listen3Exception = e;
        MessageHeaders headers = m.getHeaders();
        c.seek(new org.apache.kafka.common.TopicPartition(
                headers.get(KafkaHeaders.RECEIVED_TOPIC, String.class),
                headers.get(KafkaHeaders.RECEIVED_PARTITION_ID, Integer.class)),
                headers.get(KafkaHeaders.OFFSET, Long.class));
        return null;
    };
}