-
Notifications
You must be signed in to change notification settings - Fork 611
Replace deprecated methods to support Kafka 4.0.0 #2254
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 3 commits
5715b0d
57cb00d
2eb5a98
237d547
1dbff28
21ae74b
93bd379
db8af2b
835816c
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 | ||||
---|---|---|---|---|---|---|
|
@@ -15,14 +15,22 @@ | |||||
import org.apache.kafka.clients.producer.Producer; | ||||||
import org.apache.kafka.clients.producer.ProducerConfig; | ||||||
import org.apache.kafka.clients.producer.ProducerRecord; | ||||||
import org.apache.kafka.common.KafkaFuture; | ||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorConfig; | ||||||
import org.apache.kafka.network.SocketServerConfigs; | ||||||
import org.apache.kafka.server.config.ReplicationConfigs; | ||||||
import org.apache.kafka.server.config.ServerLogConfigs; | ||||||
import org.junit.After; | ||||||
import org.junit.Before; | ||||||
import org.junit.Test; | ||||||
import org.slf4j.Logger; | ||||||
import org.slf4j.LoggerFactory; | ||||||
ShubhamRwt marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
import java.lang.reflect.InvocationTargetException; | ||||||
import java.lang.reflect.Method; | ||||||
import java.util.Collections; | ||||||
import java.util.Map; | ||||||
import java.util.NoSuchElementException; | ||||||
import java.util.Properties; | ||||||
import java.util.concurrent.ExecutionException; | ||||||
import java.util.concurrent.atomic.AtomicInteger; | ||||||
|
@@ -32,6 +40,7 @@ | |||||
public class CruiseControlMetricsReporterAutoCreateTopicTest extends CCKafkaClientsIntegrationTestHarness { | ||||||
protected static final String TOPIC = "CruiseControlMetricsReporterTest"; | ||||||
protected static final String TEST_TOPIC = "TestTopic"; | ||||||
private static final Logger LOG = LoggerFactory.getLogger(CruiseControlMetricsReporterAutoCreateTopicTest.class); | ||||||
ShubhamRwt marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
/** | ||||||
* Setup the unit test. | ||||||
|
@@ -107,7 +116,40 @@ public void testAutoCreateMetricsTopic() throws ExecutionException, InterruptedE | |||||
Properties props = new Properties(); | ||||||
props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers()); | ||||||
AdminClient adminClient = AdminClient.create(props); | ||||||
TopicDescription topicDescription = adminClient.describeTopics(Collections.singleton(TOPIC)).values().get(TOPIC).get(); | ||||||
|
||||||
// Starting with Kafka 4.0.0, the deprecated method "values()" class is completely removed from "org.apache.kafka.clients.admin.DescribeTopicsResult" | ||||||
// so we have to use the new method "topicNameValues". | ||||||
// To make sure that the internal build pass, this logic is introduced to choose the API based on the Kafka version | ||||||
Method topicDescriptionMethod = null; | ||||||
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 would do the same for the tests, we can separate the DescribeTopicsResult method detection logic into its own method,
Suggested change
|
||||||
|
||||||
try { | ||||||
// First we try to get the topicNameValues() method | ||||||
topicDescriptionMethod = Class.forName("org.apache.kafka.clients.admin.DescribeTopicsResult").getMethod("topicNameValues"); | ||||||
} catch (ClassNotFoundException | NoSuchMethodException exception) { | ||||||
LOG.info("Failed to get method topicNameValues() from DescribeTopicsResult class since we are probably on kafka 3.0.0 or older: ", exception); | ||||||
} | ||||||
|
||||||
if (topicDescriptionMethod == null) { | ||||||
try { | ||||||
// Second we try to get the values() method | ||||||
topicDescriptionMethod = Class.forName("org.apache.kafka.clients.admin.DescribeTopicsResult").getMethod("values"); | ||||||
} catch (ClassNotFoundException | NoSuchMethodException exception) { | ||||||
LOG.info("Failed to get method values() from DescribeTopicsResult class since we are probably on kafka 3.0.0 or older: ", exception); | ||||||
} | ||||||
} | ||||||
|
||||||
Map<String, KafkaFuture<TopicDescription>> topicDescriptionMap; | ||||||
if (topicDescriptionMethod != null) { | ||||||
try { | ||||||
topicDescriptionMap = (Map<String, KafkaFuture<TopicDescription>>) topicDescriptionMethod.invoke(adminClient.describeTopics(Collections.singleton(TOPIC))); | ||||||
} catch (IllegalAccessException | InvocationTargetException e) { | ||||||
throw new RuntimeException(e); | ||||||
} | ||||||
} else { | ||||||
throw new NoSuchElementException("Unable to find both values() and topicNameValues() method in the DescribeTopicsResult class"); | ||||||
} | ||||||
|
||||||
TopicDescription topicDescription = topicDescriptionMap.get(TOPIC).get(); | ||||||
// assert that the metrics topic was created with partitions and replicas as configured for the metrics report auto-creation | ||||||
assertEquals(1, topicDescription.partitions().size()); | ||||||
assertEquals(1, topicDescription.partitions().get(0).replicas().size()); | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -8,20 +8,26 @@ | |||||
import com.linkedin.kafka.cruisecontrol.metricsreporter.metric.MetricSerde; | ||||||
import com.linkedin.kafka.cruisecontrol.metricsreporter.utils.CCEmbeddedBroker; | ||||||
import com.linkedin.kafka.cruisecontrol.metricsreporter.utils.CCKafkaClientsIntegrationTestHarness; | ||||||
|
||||||
import java.lang.reflect.InvocationTargetException; | ||||||
import java.lang.reflect.Method; | ||||||
import java.time.Duration; | ||||||
import java.util.Arrays; | ||||||
import java.util.Collections; | ||||||
import java.util.HashMap; | ||||||
import java.util.HashSet; | ||||||
import java.util.Map; | ||||||
import java.util.NoSuchElementException; | ||||||
import java.util.Properties; | ||||||
import java.util.Set; | ||||||
import java.util.concurrent.ExecutionException; | ||||||
import java.util.concurrent.TimeUnit; | ||||||
import java.util.concurrent.atomic.AtomicInteger; | ||||||
import java.util.regex.Pattern; | ||||||
import com.linkedin.kafka.cruisecontrol.metricsreporter.utils.CCKafkaTestUtils; | ||||||
import org.apache.kafka.clients.CommonClientConfigs; | ||||||
import org.apache.kafka.clients.admin.AdminClient; | ||||||
import org.apache.kafka.clients.admin.NewPartitions; | ||||||
import org.apache.kafka.clients.admin.TopicDescription; | ||||||
import org.apache.kafka.clients.consumer.Consumer; | ||||||
import org.apache.kafka.clients.consumer.ConsumerConfig; | ||||||
|
@@ -33,6 +39,7 @@ | |||||
import org.apache.kafka.clients.producer.ProducerConfig; | ||||||
import org.apache.kafka.clients.producer.ProducerRecord; | ||||||
import org.apache.kafka.clients.producer.RecordMetadata; | ||||||
import org.apache.kafka.common.KafkaFuture; | ||||||
import org.apache.kafka.common.serialization.StringDeserializer; | ||||||
import org.apache.kafka.coordinator.group.GroupCoordinatorConfig; | ||||||
import org.apache.kafka.network.SocketServerConfigs; | ||||||
|
@@ -41,19 +48,24 @@ | |||||
import org.junit.After; | ||||||
import org.junit.Before; | ||||||
import org.junit.Test; | ||||||
import org.slf4j.Logger; | ||||||
import org.slf4j.LoggerFactory; | ||||||
ShubhamRwt marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsReporter.DEFAULT_BOOTSTRAP_SERVERS_HOST; | ||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsReporter.DEFAULT_BOOTSTRAP_SERVERS_PORT; | ||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsReporterConfig.CRUISE_CONTROL_METRICS_TOPIC_AUTO_CREATE_CONFIG; | ||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsReporterConfig.CRUISE_CONTROL_METRICS_TOPIC_NUM_PARTITIONS_CONFIG; | ||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsReporterConfig.CRUISE_CONTROL_METRICS_TOPIC_REPLICATION_FACTOR_CONFIG; | ||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsUtils.CLIENT_REQUEST_TIMEOUT_MS; | ||||||
import static com.linkedin.kafka.cruisecontrol.metricsreporter.metric.RawMetricType.*; | ||||||
import static org.junit.Assert.assertEquals; | ||||||
import static org.junit.Assert.assertTrue; | ||||||
|
||||||
public class CruiseControlMetricsReporterTest extends CCKafkaClientsIntegrationTestHarness { | ||||||
protected static final String TOPIC = "CruiseControlMetricsReporterTest"; | ||||||
private static final String HOST = "127.0.0.1"; | ||||||
private static final Logger LOG = LoggerFactory.getLogger(CruiseControlMetricsReporterAutoCreateTopicTest.class); | ||||||
ShubhamRwt marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
|
||||||
/** | ||||||
* Setup the unit test. | ||||||
|
@@ -190,7 +202,42 @@ public void testUpdatingMetricsTopicConfig() throws ExecutionException, Interrup | |||||
setSecurityConfigs(props, "admin"); | ||||||
props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers()); | ||||||
AdminClient adminClient = AdminClient.create(props); | ||||||
TopicDescription topicDescription = adminClient.describeTopics(Collections.singleton(TOPIC)).values().get(TOPIC).get(); | ||||||
|
||||||
// Starting with Kafka 4.0.0, the deprecated method "values()" class is completely removed from "org.apache.kafka.clients.admin.DescribeTopicsResult" | ||||||
// so we have to use the new method "topicNameValues". | ||||||
// To make sure that the internal build pass, this logic is introduced to choose the API based on the Kafka version | ||||||
Method topicDescriptionMethod = null; | ||||||
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 would do the same for the tests, we can separate the DescribeTopicsResult method detection logic into its own method,
Suggested change
|
||||||
|
||||||
try { | ||||||
// First we try to get the topicNameValues() method | ||||||
topicDescriptionMethod = Class.forName("org.apache.kafka.clients.admin.DescribeTopicsResult").getMethod("topicNameValues"); | ||||||
} catch (ClassNotFoundException | NoSuchMethodException exception) { | ||||||
LOG.info("Failed to get method topicNameValues() from DescribeTopicsResult class since we are probably on kafka 3.0.0 or older: ", exception); | ||||||
} | ||||||
|
||||||
if (topicDescriptionMethod == null) { | ||||||
try { | ||||||
// Second we try to get the values() method | ||||||
topicDescriptionMethod = Class.forName("org.apache.kafka.clients.admin.DescribeTopicsResult").getMethod("values"); | ||||||
} catch (ClassNotFoundException | NoSuchMethodException exception) { | ||||||
LOG.info("Failed to get method values() from DescribeTopicsResult class since we are probably on kafka 3.0.0 or older: ", exception); | ||||||
} | ||||||
} | ||||||
|
||||||
Map<String, KafkaFuture<TopicDescription>> topicDescriptionMap; | ||||||
|
||||||
if (topicDescriptionMethod != null) { | ||||||
try { | ||||||
topicDescriptionMap = (Map<String, KafkaFuture<TopicDescription>>) topicDescriptionMethod.invoke(adminClient.describeTopics(Collections.singleton(TOPIC))); | ||||||
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) { | ||||||
throw new RuntimeException(e); | ||||||
} | ||||||
} else { | ||||||
throw new NoSuchElementException("Unable to find both values() and topicNameValues() method in the DescribeTopicsResult class"); | ||||||
} | ||||||
|
||||||
TopicDescription topicDescription = topicDescriptionMap.get(TOPIC).get(); | ||||||
assertEquals(1, topicDescription.partitions().size()); | ||||||
// Shutdown broker | ||||||
_brokers.get(0).shutdown(); | ||||||
|
@@ -205,7 +252,7 @@ public void testUpdatingMetricsTopicConfig() throws ExecutionException, Interrup | |||||
// Wait for broker to boot up | ||||||
Thread.sleep(5000); | ||||||
// Check whether the topic config is updated | ||||||
topicDescription = adminClient.describeTopics(Collections.singleton(TOPIC)).values().get(TOPIC).get(); | ||||||
topicDescription = topicDescriptionMap.get(TOPIC).get(); | ||||||
assertEquals(2, topicDescription.partitions().size()); | ||||||
} | ||||||
|
||||||
|
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.
It may be worth separating out the DescribeTopicsResult method detection into a separate method. This would keep the focus of the maybeIncreaseTopicPartitionCount() method on the original logic.
We could separate the DescribeTopicsResult method detection logic out like this:
Then call it like this: