chia7712 commented on code in PR #22083:
URL: https://github.com/apache/kafka/pull/22083#discussion_r3612852598


##########
clients/src/test/java/org/apache/kafka/clients/producer/KafkaProducerTest.java:
##########
@@ -1003,91 +1002,75 @@ public void testTopicRefreshInMetadata() throws 
InterruptedException {
     }
 
     @Test
-    public void testTopicNotExistingInMetadata() throws InterruptedException {
+    public void testTopicNotExistingInMetadata() {
         Map<String, Object> configs = new HashMap<>();
         configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9999");
-        configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "30000");
-        long refreshBackoffMs = 500L;
-        long refreshBackoffMaxMs = 5000L;
+        configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "2000");
+        configs.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "false");
+        long refreshBackoffMs = 50L;
+        long refreshBackoffMaxMs = 500L;
         long metadataExpireMs = 60000L;
         long metadataIdleMs = 60000L;
-        final Time time = new MockTime();
+        final Time time = Time.SYSTEM;
         final ProducerMetadata metadata = new 
ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs, 
metadataIdleMs,
-                new LogContext(), new ClusterResourceListeners(), time);
+                new LogContext(), new ClusterResourceListeners());
         final String topic = "topic";
+        MockClient client = new MockClient(time, metadata);
+        // Seed initial metadata, then update with the topic marked as 
UNKNOWN_TOPIC_OR_PARTITION
+        client.updateMetadata(RequestTestUtils.metadataUpdateWith(1, 
Map.of()));
+        MetadataResponse errorResponse = 
RequestTestUtils.metadataUpdateWith("kafka-cluster", 1,
+                singletonMap(topic, Errors.UNKNOWN_TOPIC_OR_PARTITION), 
emptyMap());
+        client.prepareMetadataUpdate(errorResponse);
         try (KafkaProducer<String, String> producer = kafkaProducer(configs, 
new StringSerializer(),
-                new StringSerializer(), metadata, new MockClient(time, 
metadata), null, time)) {
-
-            Exchanger<Void> exchanger = new Exchanger<>();
+                new StringSerializer(), metadata, client, null, time)) {
 
-            Thread t = new Thread(() -> {
-                try {
-                    // Update the metadata with non-existing topic.
-                    MetadataResponse updateResponse = 
RequestTestUtils.metadataUpdateWith("kafka-cluster", 1,
-                            singletonMap(topic, 
Errors.UNKNOWN_TOPIC_OR_PARTITION), emptyMap());
-                    metadata.updateWithCurrentRequestVersion(updateResponse, 
false, time.milliseconds());
-                    exchanger.exchange(null);
-                    while (!metadata.updateRequested())
-                        Thread.sleep(100);
-                    time.sleep(30 * 1000L);
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            });
-            t.start();
-            exchanger.exchange(null);
+            // partitionsFor should time out via real wait() because the topic 
has an error
+            // and the Sender keeps replaying the same error metadata.
             Throwable throwable = assertThrows(TimeoutException.class, () -> 
producer.partitionsFor(topic));
             assertInstanceOf(UnknownTopicOrPartitionException.class, 
throwable.getCause());
-            t.join();
         }
     }
 
     @Test
     public void testTopicExpiryInMetadata() throws InterruptedException {
         Map<String, Object> configs = new HashMap<>();
         configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9999");
-        configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "30000");
-        long refreshBackoffMs = 500L;
-        long refreshBackoffMaxMs = 5000L;
-        long metadataExpireMs = 60000L;
-        long metadataIdleMs = 60000L;
-        final Time time = new MockTime();
+        configs.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, "2000");
+        configs.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "false");
+        long refreshBackoffMs = 50L;
+        long refreshBackoffMaxMs = 500L;
+        long metadataExpireMs = 1000L;
+        long metadataIdleMs = 1000L;
+        final Time time = Time.SYSTEM;
         final ProducerMetadata metadata = new 
ProducerMetadata(refreshBackoffMs, refreshBackoffMaxMs, metadataExpireMs, 
metadataIdleMs,
-                new LogContext(), new ClusterResourceListeners(), time);
+                new LogContext(), new ClusterResourceListeners());
         final String topic = "topic";
+        MockClient client = new MockClient(time, metadata);
+        // Seed initial metadata without the topic
+        client.updateMetadata(RequestTestUtils.metadataUpdateWith(1, 
Map.of()));
+        // Queue a metadata response with the topic for the first 
partitionsFor call
+        client.prepareMetadataUpdate(RequestTestUtils.metadataUpdateWith(1, 
Map.of(topic, 1)));
+        // Queue a follow-up without the topic so that after consumption, 
updateWithCurrentMetadata
+        // replays the empty response
+        client.prepareMetadataUpdate(RequestTestUtils.metadataUpdateWith(1, 
Map.of()));
         try (KafkaProducer<String, String> producer = kafkaProducer(configs, 
new StringSerializer(),
-                new StringSerializer(), metadata, new MockClient(time, 
metadata), null, time)) {
+                new StringSerializer(), metadata, client, null, time)) {
 
-            Exchanger<Void> exchanger = new Exchanger<>();
+            // First call should succeed — the queued metadata response 
includes the topic
+            assertNotNull(producer.partitionsFor(topic));
 
-            Thread t = new Thread(() -> {
-                try {
-                    exchanger.exchange(null);  // 1
-                    while (!metadata.updateRequested())
-                        Thread.sleep(100);
-                    MetadataResponse updateResponse = 
RequestTestUtils.metadataUpdateWith(1, singletonMap(topic, 1));
-                    metadata.updateWithCurrentRequestVersion(updateResponse, 
false, time.milliseconds());
-                    exchanger.exchange(null);  // 2
-                    time.sleep(120 * 1000L);
+            // Wait for topic metadata to expire (metadataIdleMs = 1000ms)
+            Thread.sleep(1500);

Review Comment:
   This makes the test slightly slower, but I think our CI can handle the extra 
delay



##########
clients/src/main/java/org/apache/kafka/clients/producer/internals/ProducerMetadata.java:
##########
@@ -138,14 +136,19 @@ public synchronized boolean retainTopic(String topic, 
boolean isInternal, long n
     /**
      * Wait for metadata update until the current version is larger than the 
last version we know of
      */
-    public synchronized void awaitUpdate(final int lastVersion, final long 
timeoutMs) throws InterruptedException {
-        long currentTimeMs = time.milliseconds();
-        long deadlineMs = currentTimeMs + timeoutMs < 0 ? Long.MAX_VALUE : 
currentTimeMs + timeoutMs;
-        time.waitObject(this, () -> {

Review Comment:
   `waitObject` is now dead code, so we can remove the related tests and add a 
default implementation to Time, right?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to