Consuming again messages from kafka log compaction topic

前端 未结 1 972
感动是毒
感动是毒 2020-12-20 01:55

I have a spring application with a Kafka consumer using a @KafkaListerner annotation. The topic being consumed is log compacted and we might have the scenario where we m

相关标签:
1条回答
  • 2020-12-20 02:35
        @KafkaListener(...)
        public void listen(String in, @Header(KafkaHeaders.CONSUMER) Consumer<?, ?> consumer) {
            System.out.println(in);
            if (this.resetNeeded) {
                consumer.seekToBeginning(consumer.assignment());
                this.resetNeeded = false;
            }
        }
    

    If you want to reset when the listener is idle (no records) you can enable idle events and perform the seeks by listening for a ListenerContainerIdleEvent in an ApplicationListener or @EventListener method.

    The event has a reference to the consumer.

    EDIT

    @SpringBootApplication
    public class So58769796Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So58769796Application.class, args);
        }
    
        @KafkaListener(id = "so58769796", topics = "so58769796")
        public void listen1(String value, @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) String key) {
            System.out.println("One:" + key + ":" + value);
        }
    
        @KafkaListener(id = "so58769796a", topics = "so58769796")
        public void listen2(String value, @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) String key) {
            System.out.println("Two:" + key + ":" + value);
        }
    
        @Bean
        public NewTopic topic() {
            return TopicBuilder.name("so58769796")
                    .compact()
                    .partitions(1)
                    .replicas(1)
                    .build();
        }
    
        boolean reset;
    
        @Bean
        public ApplicationRunner runner(KafkaTemplate<String, String> template) {
            return args -> {
                template.send("so58769796", "foo", "bar");
                System.out.println("Hit enter to rewind");
                System.in.read();
                this.reset = true;
            };
        }
    
        @EventListener
        public void listen(ListenerContainerIdleEvent event) {
            System.out.println(event);
            if (this.reset && event.getListenerId().startsWith("so58769796-")) {
                event.getConsumer().seekToBeginning(event.getConsumer().assignment());
            }
        }
    
    }
    

    and

    spring.kafka.listener.idle-event-interval=5000
    

    EDIT2

    Here's another technique - in this case we rewind each time the app starts (and on demand)...

    @SpringBootApplication
    public class So58769796Application implements ConsumerSeekAware {
    
        public static void main(String[] args) {
            SpringApplication.run(So58769796Application.class, args);
        }
    
        @KafkaListener(id = "so58769796", topics = "so58769796")
        public void listen(String value, @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) String key) {
            System.out.println(key + ":" + value);
        }
    
        @Bean
        public NewTopic topic() {
            return TopicBuilder.name("so58769796")
                    .compact()
                    .partitions(1)
                    .replicas(1)
                    .build();
        }
    
        @Bean
        public ApplicationRunner runner(KafkaTemplate<String, String> template,
                KafkaListenerEndpointRegistry registry) {
    
            return args -> {
                template.send("so58769796", "foo", "bar");
                System.out.println("Hit enter to rewind");
                System.in.read();
                registry.getListenerContainer("so58769796").stop();
                registry.getListenerContainer("so58769796").start();
            };
    
        }
    
        @Override
        public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
            assignments.keySet().forEach(tp -> callback.seekToBeginning(tp.topic(), tp.partition()));
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题