You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by lh...@apache.org on 2024/12/20 11:17:20 UTC

(pulsar) branch master updated: [Fix][Client] Fix pending message not complete when closeAsync (#23761)

This is an automated email from the ASF dual-hosted git repository.

lhotari pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git


The following commit(s) were added to refs/heads/master by this push:
     new e0a9e4c7b5d [Fix][Client] Fix pending message not complete when closeAsync (#23761)
e0a9e4c7b5d is described below

commit e0a9e4c7b5d3533f2a1e5b7757b180168412c35e
Author: pengxiangrui127 <67...@users.noreply.github.com>
AuthorDate: Fri Dec 20 19:17:13 2024 +0800

    [Fix][Client] Fix pending message not complete when closeAsync (#23761)
---
 .../apache/pulsar/client/impl/ProducerImpl.java    |  5 ++-
 .../pulsar/client/impl/ProducerImplTest.java       | 43 ++++++++++++++++++++--
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerImpl.java
index 10e0ee2ee3d..54d337925dc 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerImpl.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ProducerImpl.java
@@ -1177,11 +1177,11 @@ public class ProducerImpl<T> extends ProducerBase<T> implements TimerTask, Conne
         CompletableFuture<Void> closeFuture = new CompletableFuture<>();
         cnx.sendRequestWithId(cmd, requestId).handle((v, exception) -> {
             cnx.removeProducer(producerId);
+            closeAndClearPendingMessages();
             if (exception == null || !cnx.ctx().channel().isActive()) {
                 // Either we've received the success response for the close producer command from the broker, or the
                 // connection did break in the meantime. In any case, the producer is gone.
                 log.info("[{}] [{}] Closed Producer", topic, producerName);
-                closeAndClearPendingMessages();
                 closeFuture.complete(null);
             } else {
                 closeFuture.completeExceptionally(exception);
@@ -1193,7 +1193,8 @@ public class ProducerImpl<T> extends ProducerBase<T> implements TimerTask, Conne
         return closeFuture;
     }
 
-    private synchronized void closeAndClearPendingMessages() {
+    @VisibleForTesting
+    protected synchronized void closeAndClearPendingMessages() {
         setState(State.Closed);
         client.cleanupProducer(this);
         PulsarClientException ex = new PulsarClientException.AlreadyClosedException(
diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/ProducerImplTest.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/ProducerImplTest.java
index f9df6375939..5f690ead6c5 100644
--- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/ProducerImplTest.java
+++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/ProducerImplTest.java
@@ -22,12 +22,19 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.withSettings;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.*;
+
 import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import io.netty.util.HashedWheelTimer;
+import org.apache.pulsar.client.api.PulsarClientException;
 import org.apache.pulsar.client.api.Schema;
+import org.apache.pulsar.client.impl.conf.ClientConfigurationData;
+import org.apache.pulsar.client.impl.conf.ProducerConfigurationData;
 import org.apache.pulsar.client.impl.metrics.LatencyHistogram;
+import org.apache.pulsar.client.impl.metrics.InstrumentProvider;
 import org.apache.pulsar.common.api.proto.MessageMetadata;
 import org.mockito.Mockito;
 import org.testng.annotations.Test;
@@ -68,4 +75,34 @@ public class ProducerImplTest {
         verify(msg).setSchemaState(MessageImpl.SchemaState.Ready);
     }
 
+    @Test
+    public void testClearPendingMessageWhenCloseAsync() {
+        PulsarClientImpl client = mock(PulsarClientImpl.class);
+        Mockito.doReturn(1L).when(client).newProducerId();
+        ClientConfigurationData clientConf = new ClientConfigurationData();
+        clientConf.setStatsIntervalSeconds(-1);
+        Mockito.doReturn(clientConf).when(client).getConfiguration();
+        Mockito.doReturn(new InstrumentProvider(null)).when(client).instrumentProvider();
+        ConnectionPool connectionPool = mock(ConnectionPool.class);
+        Mockito.doReturn(1).when(connectionPool).genRandomKeyToSelectCon();
+        Mockito.doReturn(connectionPool).when(client).getCnxPool();
+        HashedWheelTimer timer = mock(HashedWheelTimer.class);
+        Mockito.doReturn(null).when(timer).newTimeout(Mockito.any(), Mockito.anyLong(), Mockito.any());
+        Mockito.doReturn(timer).when(client).timer();
+        ProducerConfigurationData producerConf = new ProducerConfigurationData();
+        producerConf.setSendTimeoutMs(-1);
+        ProducerImpl<?> producer = Mockito.spy(new ProducerImpl<>(client, "topicName", producerConf, null, 0, null, null, Optional.empty()));
+        
+        // make sure throw exception when send request to broker
+        ClientCnx clientCnx = mock(ClientCnx.class);
+        CompletableFuture<ProducerResponse> tCompletableFuture = new CompletableFuture<>();
+        tCompletableFuture.completeExceptionally(new PulsarClientException("error"));
+        when(clientCnx.sendRequestWithId(Mockito.any(), Mockito.anyLong())).thenReturn(tCompletableFuture);
+        Mockito.doReturn(clientCnx).when(producer).cnx();
+
+        // run closeAsync and verify
+        CompletableFuture<Void> voidCompletableFuture = producer.closeAsync();
+        verify(producer).closeAndClearPendingMessages();
+    }
+
 }