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

frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 1afdb68b CASSSIDECAR-178: Stopping Sidecar can take a long time (#162)
1afdb68b is described below

commit 1afdb68bea7aef495a3cdc895b778fc4ea2c72e0
Author: Francisco Guerrero <fran...@apache.org>
AuthorDate: Thu Dec 12 16:48:45 2024 -0800

    CASSSIDECAR-178: Stopping Sidecar can take a long time (#162)
    
    Patch by Francisco Guerrero; Reviewed by Yifan Cai for CASSSIDECAR-178
---
 CHANGES.txt                                        |  1 +
 .../apache/cassandra/sidecar/server/Server.java    | 43 ++++++++++++++++++----
 .../cassandra/sidecar/server/ServerTest.java       | 36 ++++++++++++++++++
 3 files changed, 73 insertions(+), 7 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 1c8d31a7..70cabce9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 1.0.0
 -----
+ * Stopping Sidecar can take a long time (CASSSIDECAR-178)
  * Add support for operational job management of long-running node operations 
(CASSSIDECAR-150)
  * CDC directory not initialized properly in InstanceMetadata (CASSSIDECAR-171)
  * yaml configuration defaults to a file that doesn't exist (CASSSIDECAR-122)
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/server/Server.java 
b/server/src/main/java/org/apache/cassandra/sidecar/server/Server.java
index 824c0e6e..15500bdb 100644
--- a/server/src/main/java/org/apache/cassandra/sidecar/server/Server.java
+++ b/server/src/main/java/org/apache/cassandra/sidecar/server/Server.java
@@ -46,6 +46,7 @@ import io.vertx.core.json.JsonObject;
 import io.vertx.core.net.SSLOptions;
 import io.vertx.core.net.TrafficShapingOptions;
 import io.vertx.ext.web.Router;
+import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate;
 import org.apache.cassandra.sidecar.cluster.InstancesConfig;
 import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
 import org.apache.cassandra.sidecar.common.utils.Preconditions;
@@ -150,7 +151,7 @@ public class Server
      *
      * @return a future completed with the result
      */
-    public Future<Void> close()
+    public Future<CompositeFuture> close()
     {
         LOGGER.info("Stopping Cassandra Sidecar");
         deployedServerVerticles.clear();
@@ -161,13 +162,41 @@ public class Server
         periodicTaskExecutor.close(periodicTaskExecutorPromise);
         closingFutures.add(periodicTaskExecutorPromise.future());
 
-        instancesConfig.instances()
-                       .forEach(instance ->
-                                closingFutures.add(executorPools.internal()
-                                                                
.runBlocking(() -> instance.delegate().close())));
+        instancesConfig.instances().forEach(instance -> {
+            Promise<Void> closingFutureForInstance = Promise.promise();
+            executorPools.internal()
+                         .runBlocking(() -> {
+                             try
+                             {
+                                 CassandraAdapterDelegate delegate = 
instance.delegate();
+                                 if (delegate != null)
+                                 {
+                                     delegate.close();
+                                 }
+                             }
+                             catch (Exception e)
+                             {
+                                 LOGGER.error("Failed to close delegate", e);
+                                 closingFutureForInstance.tryFail(e);
+                             }
+                             finally
+                             {
+                                 closingFutureForInstance.tryComplete(null);
+                             }
+                         });
+            closingFutures.add(closingFutureForInstance.future());
+        });
+
         return Future.all(closingFutures)
-                     .compose(v1 -> executorPools.close())
-                     .onComplete(v -> vertx.close())
+                     .andThen(v1 -> {
+                         LOGGER.debug("Closing executor pools");
+                         executorPools.close();
+                     })
+                     .andThen(v -> {
+                         LOGGER.debug("Closing vertx");
+                         vertx.close();
+                     })
+                     .onFailure(t -> LOGGER.error("Failed to gracefully 
shutdown Cassandra Sidecar", t))
                      .onSuccess(f -> LOGGER.info("Successfully stopped 
Cassandra Sidecar"));
     }
 
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java 
b/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
index e294cd50..d4ec7012 100644
--- a/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
+++ b/server/src/test/java/org/apache/cassandra/sidecar/server/ServerTest.java
@@ -210,6 +210,42 @@ class ServerTest
         });
     }
 
+    @Test
+    @DisplayName("Server should stop immediately when there port is already in 
use")
+    void stopImmediatelyWhenPortIsInUse(VertxTestContext context)
+    {
+        long attemptStartTimeMillis = System.currentTimeMillis();
+        server.start()
+              // simulate a bind exception due to address already in use
+              .compose(deploymentId -> Future.failedFuture(new 
java.net.BindException("Address already in use")))
+              .onComplete(context.failing(result -> {
+
+                  try
+                  {
+                      server.close()
+                            .toCompletionStage()
+                            .toCompletableFuture()
+                            .get(1, TimeUnit.MINUTES);
+                  }
+                  catch (Exception e)
+                  {
+                      context.failNow(e);
+                      return;
+                  }
+
+                  long elapsedTimeMillis = System.currentTimeMillis() - 
attemptStartTimeMillis;
+                  if (elapsedTimeMillis < TimeUnit.SECONDS.toMillis(10))
+                  {
+                      context.completeNow();
+                  }
+                  else
+                  {
+                      context.failNow("Expected server close to take less than 
10000 millis, " +
+                                      "but it took " + elapsedTimeMillis + " 
millis");
+                  }
+              }));
+    }
+
     @Test
     @DisplayName("Update should fail with null options")
     void updatingTrafficShapingOptionsWithNull(VertxTestContext context)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to