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].
