Skip to content

Commit 7303413

Browse files
committed
Fix idleBetweenPolls max value calculation
- Wrong default used when `max.poll.interval.ms` is not specified - 30s Vs 300s - Value set in `@KafkaListener.properties` ignored for this calculatio and default used instead - Also use actual default for `ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG` **I will back port - expecting conflicts** * Remove unused constant
1 parent cca897b commit 7303413

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

spring-kafka/src/main/java/org/springframework/kafka/listener/KafkaMessageListenerContainer.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ public class KafkaMessageListenerContainer<K, V> // NOSONAR line count
141141
private static final boolean MICROMETER_PRESENT = ClassUtils.isPresent(
142142
"io.micrometer.core.instrument.MeterRegistry", KafkaMessageListenerContainer.class.getClassLoader());
143143

144+
private static final Map<String, Object> CONSUMER_CONFIG_DEFAULTS = ConsumerConfig.configDef().defaultValues();
145+
144146
private final AbstractMessageListenerContainer<K, V> thisOrParentContainer;
145147

146148
private final TopicPartitionOffset[] topicPartitions;
@@ -468,8 +470,6 @@ public String toString() {
468470

469471
private final class ListenerConsumer implements SchedulingAwareRunnable, ConsumerSeekCallback {
470472

471-
private static final int SIXTY = 60;
472-
473473
private static final String UNCHECKED = "unchecked";
474474

475475
private static final String RAWTYPES = "rawtypes";
@@ -615,7 +615,7 @@ private final class ListenerConsumer implements SchedulingAwareRunnable, Consume
615615

616616
@SuppressWarnings(UNCHECKED)
617617
ListenerConsumer(GenericMessageListener<?> listener, ListenerType listenerType) {
618-
Properties consumerProperties = new Properties(this.containerProperties.getKafkaConsumerProperties());
618+
Properties consumerProperties = propertiesFromProperties();
619619
checkGroupInstance(consumerProperties, KafkaMessageListenerContainer.this.consumerFactory);
620620
this.autoCommit = determineAutoCommit(consumerProperties);
621621
this.consumer =
@@ -696,6 +696,20 @@ else if (listener instanceof MessageListener) {
696696
this.micrometerHolder = obtainMicrometerHolder();
697697
}
698698

699+
private Properties propertiesFromProperties() {
700+
Properties propertyOverrides = this.containerProperties.getKafkaConsumerProperties();
701+
Properties props = new Properties();
702+
props.putAll(propertyOverrides);
703+
Set<String> stringPropertyNames = propertyOverrides.stringPropertyNames();
704+
// User might have provided properties as defaults
705+
stringPropertyNames.forEach((name) -> {
706+
if (!props.contains(name)) {
707+
props.setProperty(name, propertyOverrides.getProperty(name));
708+
}
709+
});
710+
return props;
711+
}
712+
699713
private void checkGroupInstance(Properties properties, ConsumerFactory<K, V> consumerFactory) {
700714
String groupInstance = properties.getProperty(ConsumerConfig.GROUP_INSTANCE_ID_CONFIG);
701715
if (!StringUtils.hasText(groupInstance)) {
@@ -755,9 +769,9 @@ else if (timeout instanceof String) {
755769
this.logger.warn(() -> "Unexpected type: " + timeoutToLog.getClass().getName()
756770
+ " in property '"
757771
+ ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG
758-
+ "'; defaulting to 30 seconds.");
772+
+ "'; using Kafka default.");
759773
}
760-
return Duration.ofSeconds(SIXTY / 2).toMillis(); // Default 'max.poll.interval.ms' is 30 seconds
774+
return (int) CONSUMER_CONFIG_DEFAULTS.get(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG);
761775
}
762776
}
763777

@@ -824,12 +838,12 @@ else if (timeout instanceof String) {
824838
this.logger.warn(() -> "Unexpected type: " + timeoutToLog.getClass().getName()
825839
+ " in property '"
826840
+ ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG
827-
+ "'; defaulting to 60 seconds for sync commit timeouts");
841+
+ "'; defaulting to Kafka default for sync commit timeouts");
828842
}
829-
return Duration.ofSeconds(SIXTY);
843+
return Duration
844+
.ofMillis((int) CONSUMER_CONFIG_DEFAULTS.get(ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG));
830845
}
831846
}
832-
833847
}
834848

835849
private Object findDeserializerClass(Map<String, Object> props, boolean isValue) {

spring-kafka/src/test/java/org/springframework/kafka/annotation/EnableKafkaIntegrationTests.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
import org.springframework.kafka.listener.ContainerProperties;
9292
import org.springframework.kafka.listener.ContainerProperties.AckMode;
9393
import org.springframework.kafka.listener.KafkaListenerErrorHandler;
94+
import org.springframework.kafka.listener.KafkaMessageListenerContainer;
9495
import org.springframework.kafka.listener.ListenerExecutionFailedException;
9596
import org.springframework.kafka.listener.MessageListenerContainer;
9697
import org.springframework.kafka.listener.adapter.FilteringMessageListenerAdapter;
@@ -225,6 +226,10 @@ public void testAnonymous() {
225226
List<?> containers = KafkaTestUtils.getPropertyValue(container, "containers", List.class);
226227
assertThat(KafkaTestUtils.getPropertyValue(containers.get(0), "listenerConsumer.consumerGroupId"))
227228
.isEqualTo(DEFAULT_TEST_GROUP_ID);
229+
assertThat(KafkaTestUtils.getPropertyValue(containers.get(0), "listenerConsumer.maxPollInterval"))
230+
.isEqualTo(300000L);
231+
assertThat(KafkaTestUtils.getPropertyValue(containers.get(0), "listenerConsumer.syncCommitTimeout"))
232+
.isEqualTo(Duration.ofSeconds(60));
228233
container.stop();
229234
}
230235

@@ -351,20 +356,24 @@ public void testAutoStartup() {
351356
assertThat(listenerContainer.getContainerProperties().getSyncCommitTimeout()).isNull();
352357
this.registry.start();
353358
assertThat(listenerContainer.isRunning()).isTrue();
354-
assertThat(((ConcurrentMessageListenerContainer<?, ?>) listenerContainer)
359+
KafkaMessageListenerContainer<?, ?> kafkaMessageListenerContainer =
360+
((ConcurrentMessageListenerContainer<?, ?>) listenerContainer)
355361
.getContainers()
356-
.get(0)
362+
.get(0);
363+
assertThat(kafkaMessageListenerContainer
357364
.getContainerProperties().getSyncCommitTimeout())
358-
.isEqualTo(Duration.ofSeconds(60));
365+
.isEqualTo(Duration.ofSeconds(59));
359366
assertThat(listenerContainer.getContainerProperties().getSyncCommitTimeout())
360-
.isEqualTo(Duration.ofSeconds(60));
367+
.isEqualTo(Duration.ofSeconds(59));
361368
listenerContainer.stop();
362369
assertThat(KafkaTestUtils.getPropertyValue(listenerContainer, "containerProperties.syncCommits", Boolean.class))
363370
.isFalse();
364371
assertThat(KafkaTestUtils.getPropertyValue(listenerContainer, "containerProperties.commitCallback"))
365372
.isNotNull();
366373
assertThat(KafkaTestUtils.getPropertyValue(listenerContainer, "containerProperties.consumerRebalanceListener"))
367374
.isNotNull();
375+
assertThat(KafkaTestUtils.getPropertyValue(kafkaMessageListenerContainer, "listenerConsumer.maxPollInterval"))
376+
.isEqualTo(301000L);
368377
}
369378

370379
@Test
@@ -1618,7 +1627,9 @@ static class Listener implements ConsumerSeekAware {
16181627
volatile CustomMethodArgument customMethodArgument;
16191628

16201629
@KafkaListener(id = "manualStart", topics = "manualStart",
1621-
containerFactory = "kafkaAutoStartFalseListenerContainerFactory")
1630+
containerFactory = "kafkaAutoStartFalseListenerContainerFactory",
1631+
properties = { ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG + ":301000",
1632+
ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG + ":59000" })
16221633
public void manualStart(String foo) {
16231634
}
16241635

0 commit comments

Comments
 (0)