-
Notifications
You must be signed in to change notification settings - Fork 347
fix(kafka): Call poll() during consumer pause to maintain group membership #7072
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -875,6 +875,57 @@ private ConsumerRecords createJsonRecords(String topic) throws Exception { | |
| return new ConsumerRecords(records); | ||
| } | ||
|
|
||
| @Test | ||
| public void testPauseConsumingCallsPollToMaintainGroupMembership() throws Exception { | ||
| String topic = topicConfig.getName(); | ||
| when(topicConfig.getMaxPollInterval()).thenReturn(Duration.ofMillis(4000)); | ||
|
|
||
| when(pauseConsumePredicate.pauseConsuming()).thenReturn(true); | ||
| when(kafkaConsumer.poll(any(Duration.class))).thenReturn(ConsumerRecords.empty()); | ||
| when(kafkaConsumer.assignment()).thenReturn(java.util.Collections.singleton(new TopicPartition(topic, testPartition))); | ||
|
|
||
| consumer = createObjectUnderTestWithMockBuffer("plaintext"); | ||
| consumer.onPartitionsAssigned(List.of(new TopicPartition(topic, testPartition))); | ||
|
|
||
| // Run in a thread and shut down after a short delay | ||
| Thread consumerThread = new Thread(() -> consumer.run()); | ||
| consumerThread.start(); | ||
| Thread.sleep(100); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| shutdownInProgress.set(true); | ||
| consumerThread.join(5000); | ||
|
|
||
| // Verify poll() was called even though consuming was paused | ||
| verify(kafkaConsumer, org.mockito.Mockito.atLeastOnce()).pause(any()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline FQN |
||
| verify(kafkaConsumer, org.mockito.Mockito.atLeastOnce()).poll(any(Duration.class)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline FQN |
||
| } | ||
|
|
||
| @Test | ||
| public void testPauseConsumingResumesAfterPredicateReturnsFalse() throws Exception { | ||
| String topic = topicConfig.getName(); | ||
| when(topicConfig.getMaxPollInterval()).thenReturn(Duration.ofMillis(4000)); | ||
|
|
||
| // First call returns true (paused), subsequent calls return false (resumed) | ||
| when(pauseConsumePredicate.pauseConsuming()) | ||
| .thenReturn(true) | ||
| .thenReturn(false); | ||
| when(kafkaConsumer.poll(any(Duration.class))).thenReturn(ConsumerRecords.empty()); | ||
| when(kafkaConsumer.assignment()).thenReturn(java.util.Collections.singleton(new TopicPartition(topic, testPartition))); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline FQN |
||
|
|
||
| consumer = createObjectUnderTestWithMockBuffer("plaintext"); | ||
| consumer.onPartitionsAssigned(List.of(new TopicPartition(topic, testPartition))); | ||
|
|
||
| // Need to wait longer than the 1s sleep in the pause branch for the second iteration | ||
| Thread consumerThread = new Thread(() -> consumer.run()); | ||
| consumerThread.start(); | ||
| Thread.sleep(2500); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thread.sleep(2500) is slow and timing-dependent. Please use |
||
| shutdownInProgress.set(true); | ||
| consumerThread.join(5000); | ||
|
|
||
| // Verify that consumer was paused and then resumed | ||
| verify(kafkaConsumer, org.mockito.Mockito.atLeastOnce()).pause(any()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline FQN |
||
| verify(kafkaConsumer, org.mockito.Mockito.atLeastOnce()).resume(any()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline FQN |
||
| } | ||
|
|
||
| private static Stream<Arguments> provideExceptionsFromBufferWrite() { | ||
| return Stream.of( | ||
| Arguments.of(new SizeOverflowException("size overflow")), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doPoll()result is intentionally discarded. Add a one-line comment since a rebalance mid-poll could return records that are safely re-delivered later.