Hi,
I have been trying to use the new ListenerContainerCustomizer "ListenerContainerWithDlqAndRetryCustomizer" for Kafka Binder.
I want to use it to perform a complex retry process.
After following the documentation https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/3.2.2/reference/html/spring-cloud-stream-binder-kafka.html#retry-and-dlq-processing, when I start my application, my customizer is never call, so I have performed some debugging to trying to figure out what is happening.
I have found a strange behavior in the class KafkaMessageChannelBinder, in the method "createConsumerEndpoint", line 748 and line 797.
if (!(customizer instanceof ListenerContainerWithDlqAndRetryCustomizer)
|| ((ListenerContainerWithDlqAndRetryCustomizer) customizer)
.retryAndDlqInBinding(destination.getName(), group)) {
kafkaMessageDrivenChannelAdapter
.setRetryTemplate(buildRetryTemplate(extendedConsumerProperties));
kafkaMessageDrivenChannelAdapter
.setRecoveryCallback(errorInfrastructure.getRecoverer());
}
if (customizer instanceof ListenerContainerWithDlqAndRetryCustomizer) {
BiFunction<ConsumerRecord<?, ?>, Exception, TopicPartition> destinationResolver = createDestResolver(
extendedConsumerProperties.getExtension());
BackOff createBackOff = extendedConsumerProperties.getMaxAttempts() > 1
? createBackOff(extendedConsumerProperties)
: null;
((ListenerContainerWithDlqAndRetryCustomizer) customizer)
.configure(messageListenerContainer, destination.getName(), consumerGroup, destinationResolver,
createBackOff);
}
The code is checking if the customizer is an instance of "ListenerContainerWithDlqAndRetryCustomizer", however, even when the customizer if an instance of "ListenerContainerWithDlqAndRetryCustomizer", the result if false. After investigating, I have found out that the customizer is wrap inside a Anonymous implementaton of ListenerContainerCustomizer, declare inside the DefaultBinderFactory class, line 425.

ListenerContainerCustomizer customizerWrapper = new ListenerContainerCustomizer() {
@SuppressWarnings("unchecked")
@Override
public void configure(Object container, String destinationName, String group) {
try {
customizerEntry.getValue().configure(container, destinationName, group);
}
catch (Exception e) {
logger.warn("Failed while applying ListenerContainerCustomizer. In situations when multiple "
+ "binders are used this is expected, since a particular customizer may not be applicable.");
}
}
};
((GenericApplicationContext) binderProducingContext).registerBean(customizerEntry.getKey(),
ListenerContainerCustomizer.class, () -> customizerWrapper);
Because of this wrapping, even if we declare a bean of type ListenerContainerWithDlqAndRetryCustomizer, it is wrap inside a ListenerContainerCustomizer anonymous implementation, which make the code of the class KafkaMessageChannelBinder always return false on:
customizer instanceof ListenerContainerWithDlqAndRetryCustomizer
Steps to reproduce the behavior:
Follow the documentation inside the documentation:
https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/3.2.2/reference/html/spring-cloud-stream-binder-kafka.html#retry-and-dlq-processing
Version of the framework: 3.2.2
Expected behavior: When a Bean of type ListenerContainerWithDlqAndRetryCustomizer is configured, it use as described in the documentation
Maybe I am doing something wrong in the configuration, but I haven't found out yet.
Thanks for looking into it.
Hi,
I have been trying to use the new ListenerContainerCustomizer "ListenerContainerWithDlqAndRetryCustomizer" for Kafka Binder.
I want to use it to perform a complex retry process.
After following the documentation https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/3.2.2/reference/html/spring-cloud-stream-binder-kafka.html#retry-and-dlq-processing, when I start my application, my customizer is never call, so I have performed some debugging to trying to figure out what is happening.
I have found a strange behavior in the class KafkaMessageChannelBinder, in the method "createConsumerEndpoint", line 748 and line 797.
The code is checking if the customizer is an instance of "ListenerContainerWithDlqAndRetryCustomizer", however, even when the customizer if an instance of "ListenerContainerWithDlqAndRetryCustomizer", the result if false. After investigating, I have found out that the customizer is wrap inside a Anonymous implementaton of ListenerContainerCustomizer, declare inside the DefaultBinderFactory class, line 425.
Because of this wrapping, even if we declare a bean of type ListenerContainerWithDlqAndRetryCustomizer, it is wrap inside a ListenerContainerCustomizer anonymous implementation, which make the code of the class KafkaMessageChannelBinder always return false on:
Steps to reproduce the behavior:
Follow the documentation inside the documentation:
https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/3.2.2/reference/html/spring-cloud-stream-binder-kafka.html#retry-and-dlq-processing
Version of the framework: 3.2.2
Expected behavior: When a Bean of type ListenerContainerWithDlqAndRetryCustomizer is configured, it use as described in the documentation
Maybe I am doing something wrong in the configuration, but I haven't found out yet.
Thanks for looking into it.