0

I want to create a program that when I send a message and an error occurred, it will retry 3 times then if it still doesn't send it will directly proceed to the dead letter (probably local). Here's what I'm working with right now. I don't know how to implement it properly because I'm super new to spring kafka.

KafkaConfiguration class

public class KafkaConfiguration {
    @Bean
    public ProducerFactory<String, String> producerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, AppConfiguration.bootstrapServers);
        props.put(ProducerConfig.RETRIES_CONFIG, "3");
        props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
        props.put(ProducerConfig.ACKS_CONFIG, "all");
        props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
        props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
        props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        return new DefaultKafkaProducerFactory<>(props);
    }

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

    @Bean
    public ConsumerFactory<Object, Object> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerProperties());
    }

    @Bean
    public Map<String, Object> consumerProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, AppConfiguration.bootstrapServers);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, AppConfiguration.groupid);
        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
        props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 15000);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        return props;
    }

    @Bean
    ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(
            ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
            ObjectProvider<ConsumerFactory<Object, Object>> kafkaConsumerFactory, RetryTemplate retryTemplate) {
        ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
        configurer.configure(factory, (ConsumerFactory<Object, Object>) kafkaConsumerFactory);
        factory.setRetryTemplate(retryTemplate);
        factory.setRecoveryCallback(context -> {
            log.error("RetryPolicy limit has been exceeded!");
            return null;
        });
        return factory;
    }

    @Bean
    RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(1000l);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(3);
        retryTemplate.setRetryPolicy(retryPolicy);

        return retryTemplate;
    }


}

KafkaApplication class

public class KafkaApplication {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(KafkaApplication.class, args);
        TestBean testBean = context.getBean(TestBean.class);
        while(true){
            for (int i = 0; i < 50; i++) {
                try{
                    Thread.sleep(5000);

                } catch (Exception e){
                    System.out.println("exception" + e.getMessage());
                }
                testBean.send("This is message " + i);
            }
            context.getBean(Consumer.Listener.class).latch.await(60, TimeUnit.SECONDS);
        }

    }

    @Bean
    public TestBean test() {
        return new TestBean();
    }

    @Bean
    public Consumer.Listener listener() {
        return new Consumer.Listener();
    }

    public static class TestBean {
        @Autowired
        private KafkaTemplate<String, String> template;

        public void send(String message) {
            this.template.send(AppConfiguration.topic, message);
            this.template.flush();
        }
    }
}

Consumer class

public class Consumer {


    public static class Listener {
        public final CountDownLatch latch = new CountDownLatch(3);
        private final Logger logger = LoggerFactory.getLogger(Consumer.class);

        @KafkaListener(topics = AppConfiguration.topic, groupId = AppConfiguration.groupid, containerFactory = "kafkaListenerContainerFactory")
        public void listen(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) {
            try{
                if (message.startsWith("fail")) {
                    throw new RuntimeException("failed");
                }
                System.out.println("Successfully Received: " + message + " (partition: " + partition + ")");
                this.latch.countDown();
            } catch (Exception e){
                System.out.println("Error in sending record");
                System.out.println(e);
                e.printStackTrace();
            }
        }
    }
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
James Bond
  • 25
  • 1
  • 7

0 Answers0