Six consumers on two partitions under a consumer group, a share group with the default share.acquire.mode and a share group with record_limit; the three acknowledgement types and a record that is released until Kafka stops redelivering it; a new share group starting at latest; the ordering a share group gives up; and Spring Kafka's share containers in implicit and manual acknowledgement modes. Tests run against a real broker (scripts/broker-up.sh) and write output/. Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lm655hdgDo5xsSLNomgdsy
54 lines
2.2 KiB
Java
54 lines
2.2 KiB
Java
package com.ankurm.sharegroups;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
import org.apache.kafka.clients.consumer.ConsumerConfig;
|
|
import org.apache.kafka.common.serialization.StringDeserializer;
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Configuration;
|
|
import org.springframework.kafka.annotation.EnableKafka;
|
|
import org.springframework.kafka.config.ShareKafkaListenerContainerFactory;
|
|
import org.springframework.kafka.core.DefaultShareConsumerFactory;
|
|
import org.springframework.kafka.core.ShareConsumerFactory;
|
|
import org.springframework.kafka.listener.ContainerProperties.ShareAckMode;
|
|
|
|
/**
|
|
* Spring Boot 4.1.1 does not auto-configure share consumers, so the factory and the listener container
|
|
* factories are plain beans. Two container factories: implicit (the container acknowledges for you) and
|
|
* explicit (the listener must call ShareAcknowledgment).
|
|
*/
|
|
@Configuration
|
|
@EnableKafka
|
|
public class ShareConfig {
|
|
|
|
@Bean
|
|
ShareConsumerFactory<String, String> shareConsumerFactory(@Value("${broker:localhost:9092}") String bootstrap) {
|
|
Map<String, Object> props = new HashMap<>();
|
|
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrap);
|
|
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
|
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
|
props.put("share.acquire.mode", "record_limit");
|
|
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, "3");
|
|
return new DefaultShareConsumerFactory<>(props);
|
|
}
|
|
|
|
@Bean
|
|
ShareKafkaListenerContainerFactory<String, String> implicitShareFactory(ShareConsumerFactory<String, String> factory) {
|
|
ShareKafkaListenerContainerFactory<String, String> f = new ShareKafkaListenerContainerFactory<>(factory);
|
|
f.setConcurrency(4);
|
|
f.getContainerProperties().setShareAckMode(ShareAckMode.IMPLICIT);
|
|
return f;
|
|
}
|
|
|
|
@Bean
|
|
ShareKafkaListenerContainerFactory<String, String> explicitShareFactory(ShareConsumerFactory<String, String> factory) {
|
|
ShareKafkaListenerContainerFactory<String, String> f = new ShareKafkaListenerContainerFactory<>(factory);
|
|
f.setConcurrency(2);
|
|
f.getContainerProperties().setShareAckMode(ShareAckMode.MANUAL);
|
|
return f;
|
|
}
|
|
}
|