-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-10167: use the admin client to read end-offset #8876
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
Changes from 1 commit
b9a27a8
a322765
b4589e6
a1a4bb6
7f81699
2fd0ea5
67bf693
6934cd6
ebe86f9
097dbca
8d80cce
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 |
|---|---|---|
|
|
@@ -16,6 +16,9 @@ | |
| */ | ||
| package org.apache.kafka.streams.processor.internals; | ||
|
|
||
| import org.apache.kafka.clients.admin.Admin; | ||
| import org.apache.kafka.clients.admin.ListOffsetsResult; | ||
| import org.apache.kafka.clients.admin.OffsetSpec; | ||
| import org.apache.kafka.clients.consumer.Consumer; | ||
| import org.apache.kafka.clients.consumer.ConsumerRecord; | ||
| import org.apache.kafka.clients.consumer.ConsumerRecords; | ||
|
|
@@ -43,6 +46,8 @@ | |
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.function.Function; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static org.apache.kafka.streams.processor.internals.ClientUtils.fetchCommittedOffsets; | ||
|
|
@@ -199,12 +204,19 @@ int bufferedLimitIndex() { | |
| // to update offset limit for standby tasks; | ||
| private Consumer<byte[], byte[]> mainConsumer; | ||
|
|
||
| // the changelog reader needs the admin client to list end offsets | ||
| private Admin adminClient; | ||
|
|
||
| private long lastUpdateOffsetTime; | ||
|
|
||
| void setMainConsumer(final Consumer<byte[], byte[]> consumer) { | ||
| this.mainConsumer = consumer; | ||
| } | ||
|
|
||
| void setAdminClient(final Admin adminClient) { | ||
|
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. This is not used. |
||
| this.adminClient = adminClient; | ||
| } | ||
|
|
||
| public StoreChangelogReader(final Time time, | ||
| final StreamsConfig config, | ||
| final LogContext logContext, | ||
|
|
@@ -564,8 +576,15 @@ private Map<TopicPartition, Long> endOffsetForChangelogs(final Set<TopicPartitio | |
| return Collections.emptyMap(); | ||
|
|
||
| try { | ||
| return restoreConsumer.endOffsets(partitions); | ||
| } catch (final TimeoutException e) { | ||
| if (adminClient != null) { | ||
|
Member
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. Why do we need this distinction? Seems we set
Member
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. I also do not understand the distinction. When would we want to call
Member
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. req: Could you add a test (or adapt an existing one) and verify whether during
Contributor
Author
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. This is just a hack-around: I will always use admin-client by passing it via the constructor. I will add a unit test. 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. Should we remove this check then?
Member
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. I think we can remove this
Member
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. I just saw that we kinda need to pass |
||
| final ListOffsetsResult result = adminClient.listOffsets(partitions.stream().collect( | ||
| Collectors.toMap(Function.identity(), tp -> OffsetSpec.latest()))); | ||
|
Member
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. Should we set
Contributor
Author
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. Good point, will do. |
||
| return result.all().get().entrySet().stream().collect( | ||
| Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().offset())); | ||
| } else { | ||
| return restoreConsumer.endOffsets(partitions); | ||
| } | ||
| } catch (final TimeoutException | InterruptedException | ExecutionException e) { | ||
| // if timeout exception gets thrown we just give up this time and retry in the next run loop | ||
| log.debug("Could not fetch all end offsets for {}, will retry in the next run loop", partitions); | ||
| return Collections.emptyMap(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -273,13 +273,13 @@ public boolean isRunning() { | |
| private volatile ThreadMetadata threadMetadata; | ||
| private StreamThread.StateListener stateListener; | ||
|
|
||
| private final Admin adminClient; | ||
| private final ChangelogReader changelogReader; | ||
|
|
||
| // package-private for testing | ||
| final ConsumerRebalanceListener rebalanceListener; | ||
| final Consumer<byte[], byte[]> mainConsumer; | ||
| final Consumer<byte[], byte[]> restoreConsumer; | ||
| final Admin adminClient; | ||
|
Member
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. Why is
Member
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. You mean
Contributor
Author
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. Yeah I agree, will move all these variables to private and add getters. |
||
| final InternalTopologyBuilder builder; | ||
|
|
||
| public static StreamThread create(final InternalTopologyBuilder builder, | ||
|
|
@@ -369,6 +369,7 @@ public static StreamThread create(final InternalTopologyBuilder builder, | |
|
|
||
| final Consumer<byte[], byte[]> mainConsumer = clientSupplier.getConsumer(consumerConfigs); | ||
| changelogReader.setMainConsumer(mainConsumer); | ||
| changelogReader.setAdminClient(adminClient); | ||
|
Member
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. Q: Why do you not pass the admin client in the constructor?
Contributor
Author
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. Yeah that's the plan, I was just hacking it around so that I do not need to change 30+ unit tests. Once it is confirmed to fix the issue I will refactor this PR. |
||
| taskManager.setMainConsumer(mainConsumer); | ||
|
|
||
| final StreamThread streamThread = new StreamThread( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1634,6 +1634,7 @@ public void shouldRecoverFromInvalidOffsetExceptionOnRestoreAndFinishRestore() t | |
| final StreamThread thread = createStreamThread("clientId", config, false); | ||
| final MockConsumer<byte[], byte[]> mockConsumer = (MockConsumer<byte[], byte[]>) thread.mainConsumer; | ||
| final MockConsumer<byte[], byte[]> mockRestoreConsumer = (MockConsumer<byte[], byte[]>) thread.restoreConsumer; | ||
| final MockAdminClient mockAdminClient = (MockAdminClient) thread.adminClient; | ||
|
Member
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. See my comment in |
||
|
|
||
| final TopicPartition topicPartition = new TopicPartition("topic", 0); | ||
| final Set<TopicPartition> topicPartitionSet = Collections.singleton(topicPartition); | ||
|
|
@@ -1674,7 +1675,7 @@ public void shouldRecoverFromInvalidOffsetExceptionOnRestoreAndFinishRestore() t | |
| final TopicPartition changelogPartition = new TopicPartition("stream-thread-test-count-changelog", 0); | ||
| final Set<TopicPartition> changelogPartitionSet = Collections.singleton(changelogPartition); | ||
| mockRestoreConsumer.updateBeginningOffsets(Collections.singletonMap(changelogPartition, 0L)); | ||
| mockRestoreConsumer.updateEndOffsets(Collections.singletonMap(changelogPartition, 2L)); | ||
| mockAdminClient.updateEndOffsets(Collections.singletonMap(changelogPartition, 2L)); | ||
|
|
||
| mockConsumer.schedulePollTask(() -> { | ||
| thread.setState(StreamThread.State.PARTITIONS_REVOKED); | ||
|
|
@@ -1686,7 +1687,7 @@ public void shouldRecoverFromInvalidOffsetExceptionOnRestoreAndFinishRestore() t | |
|
|
||
| TestUtils.waitForCondition( | ||
| () -> mockRestoreConsumer.assignment().size() == 1, | ||
| "Never restore first record"); | ||
| "Never get the assignment"); | ||
|
|
||
| mockRestoreConsumer.addRecord(new ConsumerRecord<>( | ||
| "stream-thread-test-count-changelog", | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.