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();