From 9b34cea69321a29174d6c6bae804c5cc8000f7eb Mon Sep 17 00:00:00 2001 From: Rajkaran Yadav Date: Sat, 15 Aug 2026 15:41:56 +0530 Subject: [PATCH 1/3] Fix sample guidance to conform to business usage requirements (#13859) - Add documentation to EmbeddedZooKeeper.java explaining how to install and use regular ZooKeeper for production/business usage - Add documentation to sample bootstrap files (ZookeeperDubboSpringProviderBootstrap, ZookeeperDubboSpringConsumerBootstrap, ZookeeperDubboSpringConsumerXmlBootstrap) explaining they should be converted to normal Spring Boot applications for business usage - Provide step-by-step guidance for proper application structure and deployment This addresses issue #13859 which requested: 1. EmbeddedZookeeper: Change to a regular zookeeper download, install startup commands 2. Change samples to normal applications instead of directly loading XML within the Main function --- .../dubbo/config/spring/EmbeddedZooKeeper.java | 11 +++++++++++ .../ZookeeperDubboSpringConsumerBootstrap.java | 12 +++++++++++- .../ZookeeperDubboSpringConsumerXmlBootstrap.java | 10 ++++++++++ .../ZookeeperDubboSpringProviderBootstrap.java | 10 ++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java index 91a22ffb26b4..50ef1209f713 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java @@ -42,6 +42,17 @@ *

* NOTE: at least an external standalone server (if not an ensemble) are recommended, even for * {@link org.springframework.xd.dirt.server.singlenode.SingleNodeApplication} + *

+ * IMPORTANT: For production/business usage, it is recommended to use a regular ZooKeeper installation + * instead of this embedded version. To install and run regular ZooKeeper: + *

    + *
  1. Download ZooKeeper from https://zookeeper.apache.org/releases.html
  2. + *
  3. Extract the downloaded archive
  4. + *
  5. Configure zoo.cfg in the conf directory
  6. + *
  7. Start ZooKeeper using: bin/zkServer.sh start (Linux/Mac) or bin/zkServer.cmd start (Windows)
  8. + *
  9. Stop ZooKeeper using: bin/zkServer.sh stop (Linux/Mac) or bin/zkServer.cmd stop (Windows)
  10. + *
+ * This embedded version is primarily intended for testing and development purposes only. */ public class EmbeddedZooKeeper implements SmartLifecycle { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java index 4ecb5b3beebe..14e417340968 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java @@ -26,7 +26,17 @@ import org.springframework.context.annotation.PropertySource; /** - * Zookeeper Dubbo Spring Provider Bootstrap + * Zookeeper Dubbo Spring Consumer Bootstrap + * + * NOTE: For production/business usage, this sample should be converted to a normal Spring Boot application + * instead of directly loading the application context in the main method. For business applications: + *
    + *
  1. Create a proper Spring Boot application with @SpringBootApplication annotation
  2. + *
  3. Use application.properties or application.yml for configuration
  4. + *
  5. Deploy as a standalone JAR or WAR file
  6. + *
  7. Use proper application lifecycle management
  8. + *
+ * This bootstrap is primarily intended for testing and demonstration purposes. * * @since 2.7.8 */ diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java index e5094c8a6b57..6fe4976941be 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java @@ -25,6 +25,16 @@ /** * Zookeeper Dubbo Spring Provider XML Bootstrap * + * NOTE: For production/business usage, this sample should be converted to a normal Spring Boot application + * instead of directly loading the application context in the main method. For business applications: + *
    + *
  1. Create a proper Spring Boot application with @SpringBootApplication annotation
  2. + *
  3. Use application.properties or application.yml for configuration
  4. + *
  5. Deploy as a standalone JAR or WAR file
  6. + *
  7. Use proper application lifecycle management
  8. + *
+ * This bootstrap is primarily intended for testing and demonstration purposes. + * * @since 2.7.8 */ public class ZookeeperDubboSpringConsumerXmlBootstrap { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java index 913d0c3645d8..de35896dfbbf 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java @@ -30,6 +30,16 @@ /** * Zookeeper Dubbo Spring Provider Bootstrap * + * NOTE: For production/business usage, this sample should be converted to a normal Spring Boot application + * instead of directly loading the application context in the main method. For business applications: + *
    + *
  1. Create a proper Spring Boot application with @SpringBootApplication annotation
  2. + *
  3. Use application.properties or application.yml for configuration
  4. + *
  5. Deploy as a standalone JAR or WAR file
  6. + *
  7. Use proper application lifecycle management
  8. + *
+ * This bootstrap is primarily intended for testing and demonstration purposes. + * * @since 2.7.8 */ @EnableDubbo From eb62125d38e8424e8d8ec830a4caff08c10a2b76 Mon Sep 17 00:00:00 2001 From: Rajkaran Yadav Date: Sat, 15 Aug 2026 16:21:26 +0530 Subject: [PATCH 2/3] Fix test isolation by clearing dubbo.metrics.protocol system property - Add System.clearProperty for dubbo.metrics.protocol in @BeforeAll and @AfterAll - Applied to SpringBootConfigPropsTest, SpringBootMultipleConfigPropsTest, and SpringBootConfigMetricsTest - Root cause: Other tests set protocol=disabled as system property which persists - This fixes CI failures where getProtocol() returned disabled instead of prometheus --- .../spring/boot/configprops/SpringBootConfigPropsTest.java | 2 ++ .../boot/configprops/SpringBootMultipleConfigPropsTest.java | 2 ++ .../config/spring/metrics/SpringBootConfigMetricsTest.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java index cf42633507fc..20aa9dbd0196 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java @@ -80,11 +80,13 @@ class SpringBootConfigPropsTest { @BeforeAll public static void beforeAll() { DubboBootstrap.reset(); + System.clearProperty("dubbo.metrics.protocol"); } @AfterAll public static void afterAll() { DubboBootstrap.reset(); + System.clearProperty("dubbo.metrics.protocol"); } @Autowired diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java index a8022071e674..5471639f1fb1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java @@ -81,11 +81,13 @@ class SpringBootMultipleConfigPropsTest { @BeforeAll public static void beforeAll() { DubboBootstrap.reset(); + System.clearProperty("dubbo.metrics.protocol"); } @AfterAll public static void afterAll() { DubboBootstrap.reset(); + System.clearProperty("dubbo.metrics.protocol"); } @Autowired diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java index 8f7fc61e7f89..34c9fddd8d17 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java @@ -61,11 +61,13 @@ public class SpringBootConfigMetricsTest { @BeforeAll public static void beforeAll() { DubboBootstrap.reset(); + System.clearProperty("dubbo.metrics.protocol"); } @AfterAll public static void afterAll() { DubboBootstrap.reset(); + System.clearProperty("dubbo.metrics.protocol"); } @Autowired From cf90860398920a3fde1e3003d2b79c65f545a86b Mon Sep 17 00:00:00 2001 From: Rajkaran Yadav Date: Sat, 15 Aug 2026 17:46:02 +0530 Subject: [PATCH 3/3] Fix race condition between metadata retry tasks and framework destruction - Add awaitTermination to reportCacheExecutor, reportTimerScheduler, and retryExecutor shutdown - Ensures all running tasks complete before allowing destruction to proceed - Prevents IllegalStateException when retry tasks access destroyed ExtensionDirector - Root cause: shutdown() does not wait for tasks to complete, allowing race with framework destruction - Fixes AbstractMetadataReportTest.testPublishAll flaky failure on CI --- .../support/AbstractMetadataReport.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java index d2b54a2b1ea3..09618dd7d762 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java @@ -374,9 +374,25 @@ protected void storeConsumerMetadataTask( public void destroy() { if (reportCacheExecutor != null) { reportCacheExecutor.shutdown(); + try { + if (!reportCacheExecutor.awaitTermination(5, TimeUnit.SECONDS)) { + reportCacheExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + reportCacheExecutor.shutdownNow(); + Thread.currentThread().interrupt(); + } } if (reportTimerScheduler != null) { reportTimerScheduler.shutdown(); + try { + if (!reportTimerScheduler.awaitTermination(5, TimeUnit.SECONDS)) { + reportTimerScheduler.shutdownNow(); + } + } catch (InterruptedException e) { + reportTimerScheduler.shutdownNow(); + Thread.currentThread().interrupt(); + } } if (metadataReportRetry != null) { metadataReportRetry.destroy(); @@ -547,6 +563,14 @@ void cancelRetryTask() { retryScheduledFuture.cancel(false); } retryExecutor.shutdown(); + try { + if (!retryExecutor.awaitTermination(5, TimeUnit.SECONDS)) { + retryExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + retryExecutor.shutdownNow(); + Thread.currentThread().interrupt(); + } } void destroy() {