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

wujimin pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git

commit 03da433f3f1b85afe155b176c45156d9f96bde35
Author: zhengyangyong <[email protected]>
AuthorDate: Fri May 11 14:37:27 2018 +0800

    SCB-548 improve gracefully shutdown
    
    Signed-off-by: zhengyangyong <[email protected]>
---
 .../servicecomb/core/CseApplicationListener.java   | 35 ++++++++++++----
 .../core/handler/ShutdownHookHandler.java          | 46 ++++++++++------------
 2 files changed, 48 insertions(+), 33 deletions(-)

diff --git 
a/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java 
b/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java
index 0cd57f6..24da8c2 100644
--- a/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java
+++ b/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java
@@ -26,6 +26,7 @@ import org.apache.servicecomb.core.BootListener.EventType;
 import org.apache.servicecomb.core.definition.loader.SchemaListenerManager;
 import org.apache.servicecomb.core.endpoint.AbstractEndpointsCache;
 import org.apache.servicecomb.core.handler.HandlerConfigUtils;
+import org.apache.servicecomb.core.handler.ShutdownHookHandler;
 import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager;
 import org.apache.servicecomb.core.provider.consumer.ReferenceConfigUtils;
 import org.apache.servicecomb.core.provider.producer.ProducerProviderManager;
@@ -146,18 +147,36 @@ public class CseApplicationListener
       }
     } else if (event instanceof ContextClosedEvent) {
       LOGGER.warn("cse is closing now...");
-      triggerEvent(EventType.BEFORE_CLOSE);
-
-      //Unregister microservice instance from Service Center and close vertx
-      //We need unregister from service center immediately
-      RegistryUtils.destroy();
-      VertxUtils.closeVertxByName("registry");
-
-      triggerEvent(EventType.AFTER_CLOSE);
+      gracefullyShutdown();
       isInit = false;
     }
   }
 
+  private void gracefullyShutdown() {
+    //Step 1: Unregister microservice instance from Service Center and close 
vertx
+    //        We need unregister from service center immediately
+    RegistryUtils.destroy();
+    VertxUtils.closeVertxByName("registry");
+
+    //Step 2: wait all invocation finished
+    try {
+      ShutdownHookHandler.INSTANCE.ALL_INVOCATION_FINISHED.acquire();
+      LOGGER.warn("all invocation finished");
+    } catch (InterruptedException e) {
+      LOGGER.error("invocation finished semaphore interrupted", e);
+    }
+
+    //Step 3: notify all component do clean works via Event
+    triggerEvent(EventType.BEFORE_CLOSE);
+
+    //Step 4: Stop vertx to prevent blocking exit
+    VertxUtils.closeVertxByName("config-center");
+    VertxUtils.closeVertxByName("transport");
+
+    triggerEvent(EventType.AFTER_CLOSE);
+    ShutdownHookHandler.INSTANCE.ALL_INVOCATION_FINISHED.release();
+  }
+
 
   /**
    * <p>As the process of instance registry is asynchronous, the {@code 
AFTER_REGISTRY}
diff --git 
a/core/src/main/java/org/apache/servicecomb/core/handler/ShutdownHookHandler.java
 
b/core/src/main/java/org/apache/servicecomb/core/handler/ShutdownHookHandler.java
index 019aab2..4b284a4 100644
--- 
a/core/src/main/java/org/apache/servicecomb/core/handler/ShutdownHookHandler.java
+++ 
b/core/src/main/java/org/apache/servicecomb/core/handler/ShutdownHookHandler.java
@@ -17,19 +17,19 @@
 
 package org.apache.servicecomb.core.handler;
 
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.servicecomb.core.Handler;
 import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.foundation.vertx.VertxUtils;
+import 
org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.swagger.invocation.AsyncResponse;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * 实现调用链的优雅停止: 当调用链没有返回的时候,等待返回或者超时
+ * 实现调用链的优雅停止: 当调用链没有返回的时候,等待返回(由于Consumer存在超时,所以必定能够返回)
  */
 public final class ShutdownHookHandler implements Handler, Runnable {
   private static final Logger LOG = 
LoggerFactory.getLogger(ShutdownHookHandler.class);
@@ -40,13 +40,16 @@ public final class ShutdownHookHandler implements Handler, 
Runnable {
 
   private final AtomicLong responseCounter = new AtomicLong(0);
 
-  private final int timeout = 600;
-
-  private final int period = 10;
-
   private volatile boolean shuttingDown = false;
 
+  public final Semaphore ALL_INVOCATION_FINISHED = new Semaphore(1);
+
   private ShutdownHookHandler() {
+    try {
+      ALL_INVOCATION_FINISHED.acquire();
+    } catch (InterruptedException e) {
+      throw new ServiceCombException("init invocation finished semaphore 
failed", e);
+    }
     Runtime.getRuntime().addShutdownHook(new Thread(this));
   }
 
@@ -63,7 +66,7 @@ public final class ShutdownHookHandler implements Handler, 
Runnable {
     }
 
     // TODO:统计功能应该独立出来,在链中统计,会有各种bug
-    //      下面的两次catch,可能会导致一次请求,对应2次应答
+    // 下面的两次catch,可能会导致一次请求,对应2次应答
     requestCounter.incrementAndGet();
     try {
       invocation.next(resp -> {
@@ -71,33 +74,26 @@ public final class ShutdownHookHandler implements Handler, 
Runnable {
           asyncResp.handle(resp);
         } finally {
           responseCounter.incrementAndGet();
+          validAllInvocationFinished();
         }
       });
     } catch (Throwable e) {
       responseCounter.incrementAndGet();
+      validAllInvocationFinished();
       throw e;
     }
   }
 
+  private synchronized void validAllInvocationFinished() {
+    if (shuttingDown && getActiveCount() <= 0) {
+      ALL_INVOCATION_FINISHED.release();
+    }
+  }
+
   @Override
   public void run() {
     shuttingDown = true;
-    LOG.warn("handler chain is shutting down");
-    int time = 0;
-    while (getActiveCount() != 0 && time <= timeout) {
-      try {
-        TimeUnit.SECONDS.sleep(period);
-      } catch (InterruptedException e) {
-        LOG.warn(e.getMessage());
-      }
-      time = time + period;
-      LOG.warn("waiting invocation to finish in seconds " + time);
-    }
-
-    //Stop vertx to prevent blocking exit, this work need do after invocation 
waiting timeout
-    VertxUtils.closeVertxByName("config-center");
-    VertxUtils.closeVertxByName("transport");
-
-    LOG.warn("handler chain is shut down");
+    LOG.warn("handler chain is shutting down...");
+    validAllInvocationFinished();
   }
 }

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to