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

wankai123 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new bf0fe4bac6 fix: do not read runtime-rule storage if the feature is 
disabled. (#13890)
bf0fe4bac6 is described below

commit bf0fe4bac6ba212c9a6e67e6d60ca297337b454f
Author: Wan Kai <[email protected]>
AuthorDate: Thu Jun 4 16:35:15 2026 +0800

    fix: do not read runtime-rule storage if the feature is disabled. (#13890)
---
 .../extension/DbOverrideRuntimeRuleResolver.java   |  9 ++++++++
 .../DbOverrideRuntimeRuleResolverTest.java         | 25 ++++++++++++++++++++++
 .../server/core/storage/SessionCacheCallback.java  | 14 ++++++++++++
 .../oap/server/library/module/ModuleProvider.java  |  4 ++--
 .../plugin/banyandb/BanyanDBStorageClient.java     | 25 +++++++++++++++++++---
 5 files changed, 72 insertions(+), 5 deletions(-)

diff --git 
a/oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolver.java
 
b/oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolver.java
index a8e4645c61..e9a38a4bcb 100644
--- 
a/oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolver.java
+++ 
b/oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolver.java
@@ -34,6 +34,7 @@ import 
org.apache.skywalking.oap.server.core.rule.ext.StaticRuleRegistry;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import 
org.apache.skywalking.oap.server.core.storage.management.RuntimeRuleManagementDAO;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import 
org.apache.skywalking.oap.server.receiver.runtimerule.module.RuntimeRuleModule;
 import org.yaml.snakeyaml.Yaml;
 
 /**
@@ -101,6 +102,14 @@ public final class DbOverrideRuntimeRuleResolver 
implements RuntimeRuleOverrideR
             // Test path or static-loader call without module context — 
nothing we can do.
             return Collections.emptyMap();
         }
+        if (!manager.has(RuntimeRuleModule.NAME)) {
+            // receiver-runtime-rule disabled. This resolver ships in the 
runtime-rule jar and
+            // is always discovered by ServiceLoader, so RuleSetMerger.merge() 
would otherwise
+            // drive a runtime_rule DAO read on every MAL/LAL catalog load 
even though no part
+            // of the runtime-rule feature is running. With the module off 
there are no runtime
+            // overrides to apply — serve pure disk content and never touch 
storage.
+            return Collections.emptyMap();
+        }
         synchronized (this) {
             final Map<String, Resolution> cached = cache.get(catalog);
             if (cached != null) {
diff --git 
a/oap-server/server-admin/runtime-rule/src/test/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolverTest.java
 
b/oap-server/server-admin/runtime-rule/src/test/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolverTest.java
index 59a07958ad..a7f2f147f9 100644
--- 
a/oap-server/server-admin/runtime-rule/src/test/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolverTest.java
+++ 
b/oap-server/server-admin/runtime-rule/src/test/java/org/apache/skywalking/oap/server/receiver/runtimerule/extension/DbOverrideRuntimeRuleResolverTest.java
@@ -21,12 +21,19 @@ package 
org.apache.skywalking.oap.server.receiver.runtimerule.extension;
 import java.lang.reflect.Method;
 import java.nio.charset.StandardCharsets;
 import org.apache.skywalking.oap.server.core.rule.ext.StaticRuleRegistry;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import 
org.apache.skywalking.oap.server.receiver.runtimerule.module.RuntimeRuleModule;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * Covers the layer-override-forbidden guard {@link 
DbOverrideRuntimeRuleResolver}
@@ -45,6 +52,24 @@ class DbOverrideRuntimeRuleResolverTest {
         m.invoke(StaticRuleRegistry.active());
     }
 
+    @Test
+    void disabledModuleSkipsStorageRead() {
+        // receiver-runtime-rule not in the loaded module set: the resolver 
must short-circuit
+        // before any storage access so a disabled module never drives a 
runtime_rule DAO read
+        // on the MAL/LAL static load path.
+        final ModuleManager manager = mock(ModuleManager.class);
+        when(manager.has(RuntimeRuleModule.NAME)).thenReturn(false);
+
+        assertTrue(new DbOverrideRuntimeRuleResolver().loadAll("otel-rules", 
manager).isEmpty());
+        verify(manager, never()).find(anyString());
+    }
+
+    @Test
+    void nullManagerReturnsEmpty() {
+        // No module context (tests / static-loader call without a manager) — 
serve disk content.
+        assertTrue(new DbOverrideRuntimeRuleResolver().loadAll("otel-rules", 
null).isEmpty());
+    }
+
     @Test
     void overrideWithoutLayerDefinitionsIsAllowed() {
         StaticRuleRegistry.active().record(
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/SessionCacheCallback.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/SessionCacheCallback.java
index aa0149737b..3be73c953f 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/SessionCacheCallback.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/SessionCacheCallback.java
@@ -27,6 +27,20 @@ import 
org.apache.skywalking.oap.server.core.analysis.worker.MetricsSessionCache
  */
 @RequiredArgsConstructor
 public class SessionCacheCallback {
+    /**
+     * A no-op callback that does nothing. Used by secondary backends in 
multi-write mode
+     * to avoid duplicate cache updates.
+     */
+    public static final SessionCacheCallback NOOP = new 
SessionCacheCallback(null, null) {
+        @Override
+        public void onInsertCompleted() {
+        }
+
+        @Override
+        public void onUpdateFailure() {
+        }
+    };
+
     private final MetricsSessionCache sessionCache;
     private final Metrics metrics;
     /**
diff --git 
a/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleProvider.java
 
b/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleProvider.java
index 6eeed9145d..2c8a12e0af 100644
--- 
a/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleProvider.java
+++ 
b/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleProvider.java
@@ -31,9 +31,9 @@ import lombok.Setter;
 public abstract class ModuleProvider implements ModuleServiceHolder {
     @Setter
     private ModuleManager manager;
-    @Setter(AccessLevel.PACKAGE)
+    @Setter(AccessLevel.PUBLIC)
     private ModuleDefine moduleDefine;
-    @Setter(AccessLevel.PACKAGE)
+    @Setter(AccessLevel.PUBLIC)
     private TerminalFriendlyTable bootingParameters;
     private final Map<Class<? extends Service>, Service> services = new 
HashMap<>();
 
diff --git 
a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBStorageClient.java
 
b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBStorageClient.java
index eee91772d8..e8abd2ab1e 100644
--- 
a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBStorageClient.java
+++ 
b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBStorageClient.java
@@ -146,9 +146,28 @@ public class BanyanDBStorageClient implements Client, 
HealthCheckable {
         this.client.close();
     }
 
+    /**
+     * Resolve the management schema for {@code name}, failing with a checked 
{@link IOException}
+     * rather than NPE-ing when it is not registered yet. The management model 
is installed into
+     * {@link MetadataRegistry} when the storage module starts; callers that 
run earlier in boot
+     * (e.g. the runtime-rule boot resolver loading rule overrides from
+     * {@code RuleSetMerger.merge}) can hit this method before that install 
completes. Returning a
+     * checked exception lets those callers treat it as the transient boot 
failure it is and retry,
+     * instead of crashing OAP startup. Mirrors the null guard already in
+     * {@code BanyanDBRuntimeRuleManagementDAO.save}.
+     */
+    private MetadataRegistry.Schema requireManagementSchema(String name) 
throws IOException {
+        MetadataRegistry.Schema schema = 
MetadataRegistry.INSTANCE.findManagementMetadata(name);
+        if (schema == null) {
+            throw new IOException(
+                "BanyanDB management schema for [" + name + "] is not 
registered yet");
+        }
+        return schema;
+    }
+
     public List<Property> listProperties(String name) throws IOException {
         try {
-            MetadataRegistry.Schema schema = 
MetadataRegistry.INSTANCE.findManagementMetadata(name);
+            MetadataRegistry.Schema schema = requireManagementSchema(name);
             BanyandbProperty.QueryResponse resp
                 = this.client.query(BanyandbProperty.QueryRequest.newBuilder()
                                                                  
.addGroups(schema.getMetadata().getGroup())
@@ -170,7 +189,7 @@ public class BanyanDBStorageClient implements Client, 
HealthCheckable {
 
     public Property queryProperty(String name, String id) throws IOException {
         try {
-            MetadataRegistry.Schema schema = 
MetadataRegistry.INSTANCE.findManagementMetadata(name);
+            MetadataRegistry.Schema schema = requireManagementSchema(name);
             BanyandbProperty.QueryResponse resp = 
this.client.query(BanyandbProperty.QueryRequest.newBuilder()
                                                                                
                  .addGroups(schema.getMetadata().getGroup())
                                                                                
                  .setName(name)
@@ -194,7 +213,7 @@ public class BanyanDBStorageClient implements Client, 
HealthCheckable {
 
     public DeleteResponse deleteProperty(String name, String id) throws 
IOException {
         try (HistogramMetrics.Timer timer = 
propertySingleDeleteHistogram.createTimer()) {
-            MetadataRegistry.Schema schema = 
MetadataRegistry.INSTANCE.findManagementMetadata(name);
+            MetadataRegistry.Schema schema = requireManagementSchema(name);
             PropertyStore store = new 
PropertyStore(checkNotNull(client.getChannel()));
             DeleteResponse result = 
store.delete(schema.getMetadata().getGroup(), name, id);
             this.healthChecker.health();

Reply via email to