-
Notifications
You must be signed in to change notification settings - Fork 15.4k
HOTFIX: only try to clear discover-coordinator future upon commit #12244
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 all commits
871573a
df48a52
3c707bf
ee6d74c
0642a2c
7c0d049
52c1427
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,7 @@ | |
| */ | ||
| package org.apache.kafka.clients.consumer.internals; | ||
|
|
||
| import java.time.Duration; | ||
| import java.util.SortedSet; | ||
| import java.util.TreeSet; | ||
| import org.apache.kafka.clients.GroupRebalanceConfig; | ||
|
|
@@ -548,14 +549,18 @@ public boolean poll(Timer timer, boolean waitForJoinGroup) { | |
| } | ||
| } | ||
| } else { | ||
| // For manually assigned partitions, if coordinator is unknown, make sure we lookup one and await metadata. | ||
| // For manually assigned partitions, we do not try to pro-actively lookup coordinator; | ||
| // instead we only try to refresh metadata when necessary. | ||
| // If connections to all nodes fail, wakeups triggered while attempting to send fetch | ||
| // requests result in polls returning immediately, causing a tight loop of polls. Without | ||
| // the wakeup, poll() with no channels would block for the timeout, delaying re-connection. | ||
| // awaitMetadataUpdate() in ensureCoordinatorReady initiates new connections with configured backoff and avoids the busy loop. | ||
| if (coordinatorUnknownAndUnready(timer)) { | ||
| return false; | ||
| if (metadata.updateRequested() && !client.hasReadyNodes(timer.currentTimeMs())) { | ||
| client.awaitMetadataUpdate(timer); | ||
| } | ||
|
|
||
| // if there is pending coordinator requests, ensure they have a chance to be transmitted. | ||
|
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 a major change while addressing @dajac 's comment: previously the manual assignment, the |
||
| client.pollNoWakeup(); | ||
| } | ||
|
|
||
| maybeAutoCommitOffsetsAsync(timer.currentTimeMs()); | ||
|
|
@@ -1004,7 +1009,17 @@ public RequestFuture<Void> commitOffsetsAsync(final Map<TopicPartition, OffsetAn | |
| if (offsets.isEmpty()) { | ||
| // No need to check coordinator if offsets is empty since commit of empty offsets is completed locally. | ||
| future = doCommitOffsetsAsync(offsets, callback); | ||
| } else if (!coordinatorUnknown()) { | ||
| } else if (!coordinatorUnknownAndUnready(time.timer(Duration.ZERO))) { | ||
| // we need to make sure coordinator is ready before committing, since | ||
| // this is for async committing we do not try to block, but just try once to | ||
| // clear the previous discover-coordinator future, resend, or get responses; | ||
| // if the coordinator is not ready yet then we would just proceed and put that into the | ||
| // pending requests, and future poll calls would still try to complete them. | ||
| // | ||
| // the key here though is that we have to try sending the discover-coordinator if | ||
| // it's not known or ready, since this is the only place we can send such request | ||
| // under manual assignment (there we would not have heartbeat thread trying to auto-rediscover | ||
| // the coordinator). | ||
| future = doCommitOffsetsAsync(offsets, callback); | ||
| } else { | ||
| // we don't know the current coordinator, so try to find it and then send the commit | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -514,10 +514,62 @@ public void testCoordinatorNotAvailableWithUserAssignedType() { | |
| coordinator.poll(time.timer(0)); | ||
| assertTrue(coordinator.coordinatorUnknown()); | ||
|
|
||
| // should find an available node in next find coordinator request | ||
| // should not try to find coordinator since we are in manual assignment | ||
| // hence the prepared response should not be returned | ||
| client.prepareResponse(groupCoordinatorResponse(node, Errors.NONE)); | ||
| coordinator.poll(time.timer(Long.MAX_VALUE)); | ||
| assertTrue(coordinator.coordinatorUnknown()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testAutoCommitAsyncWithUserAssignedType() { | ||
| try (ConsumerCoordinator coordinator = buildCoordinator(rebalanceConfig, new Metrics(), assignors, true, subscriptions)) { | ||
| subscriptions.assignFromUser(Collections.singleton(t1p)); | ||
| // set timeout to 0 because we expect no requests sent | ||
| coordinator.poll(time.timer(0)); | ||
| assertTrue(coordinator.coordinatorUnknown()); | ||
| assertFalse(client.hasInFlightRequests()); | ||
|
|
||
| // elapse auto commit interval and set committable position | ||
| time.sleep(autoCommitIntervalMs); | ||
| subscriptions.seekUnvalidated(t1p, new SubscriptionState.FetchPosition(100L)); | ||
|
|
||
| // should try to find coordinator since we are auto committing | ||
| coordinator.poll(time.timer(0)); | ||
| assertTrue(coordinator.coordinatorUnknown()); | ||
| assertTrue(client.hasInFlightRequests()); | ||
|
|
||
| client.respond(groupCoordinatorResponse(node, Errors.NONE)); | ||
| coordinator.poll(time.timer(0)); | ||
| assertFalse(coordinator.coordinatorUnknown()); | ||
| // after we've discovered the coordinator we should send | ||
| // out the commit request immediately | ||
| assertTrue(client.hasInFlightRequests()); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testCommitAsyncWithUserAssignedType() { | ||
| subscriptions.assignFromUser(Collections.singleton(t1p)); | ||
| // set timeout to 0 because we expect no requests sent | ||
| coordinator.poll(time.timer(0)); | ||
| assertTrue(coordinator.coordinatorUnknown()); | ||
|
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 also assert that there is not inflight requests after calling poll?
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. Ack |
||
| assertFalse(client.hasInFlightRequests()); | ||
|
|
||
| // should try to find coordinator since we are commit async | ||
| coordinator.commitOffsetsAsync(singletonMap(t1p, new OffsetAndMetadata(100L)), (offsets, exception) -> { | ||
| fail("Commit should not get responses, but got offsets:" + offsets +", and exception:" + exception); | ||
| }); | ||
| coordinator.poll(time.timer(0)); | ||
| assertTrue(coordinator.coordinatorUnknown()); | ||
| assertTrue(client.hasInFlightRequests()); | ||
|
|
||
| client.respond(groupCoordinatorResponse(node, Errors.NONE)); | ||
| coordinator.poll(time.timer(0)); | ||
| assertFalse(coordinator.coordinatorUnknown()); | ||
| // after we've discovered the coordinator we should send | ||
| // out the commit request immediately | ||
| assertTrue(client.hasInFlightRequests()); | ||
| } | ||
|
|
||
| @Test | ||
|
|
@@ -2116,8 +2168,7 @@ private void testInFlightRequestsFailedAfterCoordinatorMarkedDead(Errors error) | |
|
|
||
| @Test | ||
| public void testAutoCommitDynamicAssignment() { | ||
| try (ConsumerCoordinator coordinator = buildCoordinator(rebalanceConfig, new Metrics(), assignors, true, subscriptions) | ||
| ) { | ||
| try (ConsumerCoordinator coordinator = buildCoordinator(rebalanceConfig, new Metrics(), assignors, true, subscriptions)) { | ||
| subscriptions.subscribe(singleton(topic1), rebalanceListener); | ||
| joinAsFollowerAndReceiveAssignment(coordinator, singletonList(t1p)); | ||
| subscriptions.seek(t1p, 100); | ||
|
|
||
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.
nit: I think that we need to remove
if coordinator is unknown, make sure we lookup one andfrom the above comment (first sentence).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.
ack