DeadLetterPublishingRecoverer不会在.DLT主题上发布“原始有效负载”

时间:2019-10-17 07:46:04

标签: spring-kafka

我正在使用spring-kafka-2.2.9.RELEASEkafka_2.12-2.3.0。 我一直在尝试获取.DLT主题中的original payload,但我得到的只是“空”。我确信可以使用ErrorHandlingDeserializer2SeekToCurrentErrorHandlerDeadLetterPublishingRecoverer来做到这一点,但是我不确定自己缺少什么。

生产者和消费者

Producer:
    @Autowired
    private ObjectMapper objectMapper;

    @Bean
    public ProducerFactory<Object, Object> producerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put("acks","all");

        return new DefaultKafkaProducerFactory<Object, Object>(props, new JsonSerializer<Object>(objectMapper), new JsonSerializer<>());
        //return new DefaultKafkaProducerFactory<Object, Object>(props, new JsonSerializer<Object>(objectMapper), new JsonSerializer<Object>(objectMapper));
    }

    @Bean
    public KafkaTemplate<Object, Object> kafkaTemplate() {
        return new KafkaTemplate<Object, Object>(producerFactory());
    }

Consumer:
@Autowired
    private KafkaTemplate<Object, Object> kafkaTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Bean
    public ConsumerFactory<Object, Object> consumerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");

        JsonDeserializer<Object> jsonDeserializer = new JsonDeserializer<>(objectMapper);
        jsonDeserializer.addTrustedPackages("*");
        ErrorHandlingDeserializer2<Object> errorHandlingDeserializerKey = new ErrorHandlingDeserializer2<>(jsonDeserializer);
        ErrorHandlingDeserializer2<Object> errorHandlingDeserializerValue = new ErrorHandlingDeserializer2<>(jsonDeserializer);     

        return new DefaultKafkaConsumerFactory<>(props, errorHandlingDeserializerKey, errorHandlingDeserializerValue);
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, Object> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());

        factory.setErrorHandler(new SeekToCurrentErrorHandler(new DeadLetterPublishingRecoverer(kafkaTemplate), 3));

        return factory;
    }

我在主题中看到“空”。DLT:

kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic topic.DLT --from-beginning
null
null

在此先感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您目前无法使用2.2.x中带有@KafkaListener的DLT记录(由于序列化异常而发布),因为容器检测到DeserializationException标头,因此发送了DLT记录本身到错误处理程序。

我只有fixed this,它将在2.2.11中提供。

但是,如果您使用常规KafkaConsumer,则可以使用此代码获取原始值...

Header exHeader = record.headers().lastHeader(ErrorHandlingDeserializer2.VALUE_DESERIALIZER_EXCEPTION_HEADER);
DeserializationException ex = (DeserializationException) new ObjectInputStream(
        new ByteArrayInputStream(exHeader.value())).readObject();
System.out.println("DLT: " + new String(ex.getData()));

注意:如果您使用Artem建议的功能,那么记录将转到您的主侦听器,而不是错误处理程序,因此您必须在那里处理它。因此,您将需要某种包含原始有效负载的伪值。

如果可以升级到2.3.1,肯定会更容易。

答案 1 :(得分:0)

ErrorHandlingDeserializer2中的逻辑类似:

private T recoverFromSupplier(String topic, Headers headers, byte[] data, Exception exception) {
    if (this.failedDeserializationFunction != null) {
        FailedDeserializationInfo failedDeserializationInfo =
                new FailedDeserializationInfo(topic, headers, data, this.isForKey, exception);
        return this.failedDeserializationFunction.apply(failedDeserializationInfo);
    }
    else {
        return null;
    }
}

因此,如果未提供failedDeserializationFunction,则反序列化数据将作为null返回。

有关更多信息,请参阅文档:https://docs.spring.io/spring-kafka/docs/2.3.1.RELEASE/reference/html/#error-handling-deserializer

  

如果委托未能反序列化记录内容,则ErrorHandlingDeserializer2将在包含原因和原始字节的标头中返回空值和DeserializationException