This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.2
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.2 by this push:
new c65754681c fix issue: resolve the conficts between Dubbo shutdown hook
and Spring. (#10730)
c65754681c is described below
commit c65754681c779f4490bb9c78ff0a0e9a72a4f7a4
Author: pandaapo <[email protected]>
AuthorDate: Mon Oct 17 10:53:36 2022 +0800
fix issue: resolve the conficts between Dubbo shutdown hook and Spring.
(#10730)
---
.../org/apache/dubbo/rpc/model/ModuleModel.java | 9 +++
.../apache/dubbo/rpc/model/ModuleModelTest.java | 1 +
.../org/apache/dubbo/config/DubboShutdownHook.java | 44 +++++++++++-
.../apache/dubbo/config/DubboShutdownHookTest.java | 83 ++++++++++++++++++++++
.../spring/context/DubboSpringInitializer.java | 1 +
5 files changed, 137 insertions(+), 1 deletion(-)
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
index f94a18f2a9..1af68750f8 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
@@ -46,6 +46,7 @@ public class ModuleModel extends ScopeModel {
private ModuleServiceRepository serviceRepository;
private ModuleConfigManager moduleConfigManager;
private ModuleDeployer deployer;
+ private boolean lifeCycleManagedExternally = false;
public ModuleModel(ApplicationModel applicationModel) {
this(applicationModel, false);
@@ -196,4 +197,12 @@ public class ModuleModel extends ScopeModel {
serviceRepository.registerConsumer(consumerModel);
return consumerModel;
}
+
+ public boolean isLifeCycleManagedExternally() {
+ return lifeCycleManagedExternally;
+ }
+
+ public void setLifeCycleManagedExternally(boolean
lifeCycleManagedExternally) {
+ this.lifeCycleManagedExternally = lifeCycleManagedExternally;
+ }
}
diff --git
a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java
b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java
index f813dfb76c..c1b1c341bc 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java
@@ -40,6 +40,7 @@ public class ModuleModelTest {
Assertions.assertEquals(moduleModel.getApplicationModel(),
applicationModel);
Assertions.assertTrue(applicationModel.getPubModuleModels().contains(moduleModel));
Assertions.assertNotNull(moduleModel.getInternalId());
+ Assertions.assertFalse(moduleModel.isLifeCycleManagedExternally());
Assertions.assertNotNull(moduleModel.getExtensionDirector());
Assertions.assertNotNull(moduleModel.getBeanFactory());
diff --git
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
index 6e023d391f..988ad616df 100644
---
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
+++
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
@@ -22,7 +22,9 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static
org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_SHUTDOWN_HOOK;
@@ -77,7 +79,47 @@ public class DubboShutdownHook extends Thread {
}
private void doDestroy() {
- applicationModel.destroy();
+ boolean hasModuleBindSpring = false;
+ // check if any modules are bound to Spring
+ for (ModuleModel module: applicationModel.getModuleModels()) {
+ if (module.isLifeCycleManagedExternally()) {
+ hasModuleBindSpring = true;
+ break;
+ }
+ }
+ if (hasModuleBindSpring) {
+ int timeout =
ConfigurationUtils.getServerShutdownTimeout(applicationModel);
+ if (timeout > 0) {
+ long start = System.currentTimeMillis();
+ /**
+ * To avoid shutdown conflicts between Dubbo and Spring,
+ * wait for the modules bound to Spring to be handled by
Spring util timeout.
+ */
+ logger.info("Waiting for modules managed by Spring to be shut
down.");
+ while (!applicationModel.isDestroyed() && hasModuleBindSpring
+ && (System.currentTimeMillis() - start) < timeout) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(10);
+ hasModuleBindSpring = false;
+ if (!applicationModel.isDestroyed()) {
+ for (ModuleModel module:
applicationModel.getModuleModels()) {
+ if (module.isLifeCycleManagedExternally()) {
+ hasModuleBindSpring = true;
+ break;
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ logger.warn(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ if (!applicationModel.isDestroyed()) {
+ logger.info("Dubbo shuts down application " +
+ "after Spring fails to do in time or doesn't do it
completely.");
+ applicationModel.destroy();
+ }
}
/**
diff --git
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/DubboShutdownHookTest.java
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/DubboShutdownHookTest.java
new file mode 100644
index 0000000000..572f1a1216
--- /dev/null
+++
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/DubboShutdownHookTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.TimeUnit;
+
+import static java.util.Arrays.asList;
+
+public class DubboShutdownHookTest {
+ private DubboShutdownHook dubboShutdownHook;
+ private ApplicationModel applicationModel;
+
+ @BeforeEach
+ public void init() {
+ SysProps.setProperty(CommonConstants.IGNORE_LISTEN_SHUTDOWN_HOOK,
"false");
+ FrameworkModel frameworkModel = new FrameworkModel();
+ applicationModel = new ApplicationModel(frameworkModel);
+ ModuleModel moduleModel = applicationModel.newModule();
+ dubboShutdownHook = new DubboShutdownHook(applicationModel);
+ }
+
+ @AfterEach
+ public void clear() {
+ SysProps.clear();
+ }
+
+ @Test
+ public void testDubboShutdownHook() {
+ Assertions.assertNotNull(dubboShutdownHook);
+ Assertions.assertLinesMatch(asList("DubboShutdownHook"),
asList(dubboShutdownHook.getName()));
+ Assertions.assertFalse(dubboShutdownHook.getRegistered());
+ }
+
+ @Test
+ public void testDestoryNoModuleManagedExternally() {
+ boolean hasModuleManagedExternally = false;
+ for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+ if (moduleModel.isLifeCycleManagedExternally()) {
+ hasModuleManagedExternally = true;
+ break;
+ }
+ }
+ Assertions.assertFalse(hasModuleManagedExternally);
+ dubboShutdownHook.run();
+ Assertions.assertTrue(applicationModel.isDestroyed());
+ }
+
+ @Test
+ public void testDestoryWithModuleManagedExternally() throws
InterruptedException {
+
applicationModel.getModuleModels().get(0).setLifeCycleManagedExternally(true);
+ new Thread(() -> {
+ applicationModel.getModuleModels().get(0).destroy();
+ }).start();
+ TimeUnit.MILLISECONDS.sleep(10);
+ dubboShutdownHook.run();
+ Assertions.assertTrue(applicationModel.isDestroyed());
+ }
+}
diff --git
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
index 1fcf046854..28f277837c 100644
---
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
+++
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
@@ -138,6 +138,7 @@ public class DubboSpringInitializer {
// mark context as bound
context.markAsBound();
+ moduleModel.setLifeCycleManagedExternally(true);
// register common beans
DubboBeanUtils.registerCommonBeans(registry);