This is an automated email from the ASF dual-hosted git repository.
xiangfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new 3224ce6b796 [server] Add dynamic cluster config support to
ServerReloadJobStatusCache (#17159)
3224ce6b796 is described below
commit 3224ce6b796489d36ae69ae592f7a4964c129ac8
Author: Suvodeep Pyne <[email protected]>
AuthorDate: Thu Nov 13 13:38:53 2025 -0800
[server] Add dynamic cluster config support to ServerReloadJobStatusCache
(#17159)
* feat(server): add cluster config listener to ServerReloadJobStatusCache
Enable dynamic configuration of reload job status cache via ZooKeeper
cluster config updates, eliminating the need for server restarts when
adjusting cache parameters.
Changes:
- ServerReloadJobStatusCache now implements PinotClusterConfigChangeListener
- Added Jackson annotations to ServerReloadJobStatusCacheConfig for
automatic deserialization
- Cache rebuilds automatically on config changes with entry migration
- Registered cache as listener in BaseServerStarter
- Added comprehensive unit tests (14 test cases)
- Added AssertJ test dependency to pinot-segment-local
Supported config properties:
- pinot.server.table.reload.status.cache.max.size (default: 10000)
- pinot.server.table.reload.status.cache.ttl.days (default: 30)
* Updated ServerReloadJobStatusCacheConfig config json prop
* fix: correct config property names to size.max (not max.size)
* Removed unnecessary comments
* Removed dup const
* Updated
* Updated
* Updated
* Updated
---
pinot-segment-local/pom.xml | 5 +
.../local/utils/ServerReloadJobStatusCache.java | 99 ++++++-
.../utils/ServerReloadJobStatusCacheConfig.java | 8 +
.../utils/ServerReloadJobStatusCacheTest.java | 312 +++++++++++++++++++++
.../server/starter/helix/BaseServerStarter.java | 4 +
5 files changed, 418 insertions(+), 10 deletions(-)
diff --git a/pinot-segment-local/pom.xml b/pinot-segment-local/pom.xml
index 75c8ca4a62d..ab428b8633a 100644
--- a/pinot-segment-local/pom.xml
+++ b/pinot-segment-local/pom.xml
@@ -99,6 +99,11 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.pinot</groupId>
<artifactId>pinot-avro</artifactId>
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCache.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCache.java
index 893b1adce15..6c576dca1d3 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCache.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCache.java
@@ -18,11 +18,18 @@
*/
package org.apache.pinot.segment.local.utils;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.pinot.spi.config.provider.PinotClusterConfigChangeListener;
+import org.apache.pinot.spi.env.PinotConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,26 +42,29 @@ import static java.util.Objects.requireNonNull;
*
* <p>Thread-safe for concurrent access. Uses Guava Cache with LRU eviction
* and time-based expiration.
+ *
+ * <p>Implements PinotClusterConfigChangeListener to support dynamic
configuration
+ * updates from ZooKeeper cluster config. When config changes, cache is rebuilt
+ * with new settings and existing entries are migrated.
*/
@ThreadSafe
-public class ServerReloadJobStatusCache {
+public class ServerReloadJobStatusCache implements
PinotClusterConfigChangeListener {
private static final Logger LOG =
LoggerFactory.getLogger(ServerReloadJobStatusCache.class);
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ static final String CONFIG_PREFIX = "pinot.server.table.reload.status.cache";
- private final Cache<String, ReloadJobStatus> _cache;
+ private volatile Cache<String, ReloadJobStatus> _cache;
+ private volatile ServerReloadJobStatusCacheConfig _currentConfig;
- /**
- * Creates a cache with the given configuration.
- *
- */
public ServerReloadJobStatusCache() {
- final ServerReloadJobStatusCacheConfig config = new
ServerReloadJobStatusCacheConfig();
+ _currentConfig = new ServerReloadJobStatusCacheConfig();
_cache = CacheBuilder.newBuilder()
- .maximumSize(config.getMaxSize())
- .expireAfterWrite(config.getTtlDays(), TimeUnit.DAYS)
+ .maximumSize(_currentConfig.getMaxSize())
+ .expireAfterWrite(_currentConfig.getTtlDays(), TimeUnit.DAYS)
.recordStats()
.build();
- LOG.info("Initialized ReloadJobStatusCache with {}", config);
+ LOG.info("Initialized ReloadJobStatusCache with {}", _currentConfig);
}
/**
@@ -92,4 +102,73 @@ public class ServerReloadJobStatusCache {
}
return status;
}
+
+ /**
+ * Rebuilds the cache with new configuration and migrates existing entries.
+ * This method is synchronized to prevent concurrent rebuilds.
+ *
+ * @param newConfig new cache configuration to apply
+ */
+ private synchronized void rebuildCache(ServerReloadJobStatusCacheConfig
newConfig) {
+ LOG.info("Rebuilding reload status cache with new config: {}", newConfig);
+
+ // Create new cache with new configuration
+ Cache<String, ReloadJobStatus> newCache = CacheBuilder.newBuilder()
+ .maximumSize(newConfig.getMaxSize())
+ .expireAfterWrite(newConfig.getTtlDays(), TimeUnit.DAYS)
+ .recordStats()
+ .build();
+
+ // Migrate existing entries from old cache to new cache
+ Cache<String, ReloadJobStatus> oldCache = _cache;
+ if (oldCache != null) {
+ newCache.putAll(oldCache.asMap());
+ }
+
+ _cache = newCache;
+ _currentConfig = newConfig;
+
+ LOG.info("Successfully rebuilt reload status cache (size: {})",
newCache.size());
+ }
+
+ /**
+ * Maps cluster configuration properties with a common prefix to a config
POJO using Jackson.
+ * Uses PinotConfiguration.subset() to extract properties with the given
prefix and
+ * Jackson's convertValue() for automatic object mapping.
+ *
+ * @param clusterConfigs map of all cluster configs from ZooKeeper
+ * @param configPrefix prefix to filter configs (e.g.,
"pinot.server.table.reload.status.cache")
+ * @return ServerReloadJobStatusCacheConfig with values from cluster config,
defaults for missing values
+ */
+ @VisibleForTesting
+ static ServerReloadJobStatusCacheConfig buildFromClusterConfig(Map<String,
String> clusterConfigs,
+ String configPrefix) {
+ final MapConfiguration mapConfig = new MapConfiguration(clusterConfigs);
+ final PinotConfiguration subsetConfig = new
PinotConfiguration(mapConfig).subset(configPrefix);
+ return OBJECT_MAPPER.convertValue(subsetConfig.toMap(),
ServerReloadJobStatusCacheConfig.class);
+ }
+
+ @VisibleForTesting
+ public ServerReloadJobStatusCacheConfig getCurrentConfig() {
+ return _currentConfig;
+ }
+
+ @Override
+ public void onChange(Set<String> changedConfigs, Map<String, String>
clusterConfigs) {
+ boolean hasRelevantChanges = changedConfigs.stream()
+ .anyMatch(key -> key.startsWith(CONFIG_PREFIX));
+
+ if (!hasRelevantChanges) {
+ LOG.info("No reload cache config changes detected, skipping rebuild");
+ return;
+ }
+
+ try {
+ ServerReloadJobStatusCacheConfig newConfig =
buildFromClusterConfig(clusterConfigs, CONFIG_PREFIX);
+ rebuildCache(newConfig);
+ LOG.info("Successfully rebuilt cache with updated configuration");
+ } catch (Exception e) {
+ LOG.error("Failed to rebuild cache from cluster config, keeping existing
cache", e);
+ }
+ }
}
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheConfig.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheConfig.java
index 884ab12b28b..304e2221b17 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheConfig.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheConfig.java
@@ -18,12 +18,20 @@
*/
package org.apache.pinot.segment.local.utils;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
/**
* Configuration for ReloadJobStatusCache.
+ * Uses Jackson annotations for automatic JSON mapping from
ClusterConfiguration.
*/
+@JsonIgnoreProperties(ignoreUnknown = true)
public class ServerReloadJobStatusCacheConfig {
+ @JsonProperty("size.max")
private int _maxSize = 10000;
+
+ @JsonProperty("ttl.days")
private int _ttlDays = 30;
public int getMaxSize() {
diff --git
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheTest.java
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheTest.java
new file mode 100644
index 00000000000..1d18ece7489
--- /dev/null
+++
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/ServerReloadJobStatusCacheTest.java
@@ -0,0 +1,312 @@
+/**
+ * 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.pinot.segment.local.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+/**
+ * Unit tests for ServerReloadJobStatusCache to verify correct config injection
+ * when onChange is called, cache rebuild logic, and entry migration.
+ */
+public class ServerReloadJobStatusCacheTest {
+
+ @Test
+ public void testDefaultConfigInitialization() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // Then
+ ServerReloadJobStatusCacheConfig config = cache.getCurrentConfig();
+ assertThat(config).isNotNull();
+ assertThat(config.getMaxSize()).isEqualTo(10000);
+ assertThat(config.getTtlDays()).isEqualTo(30);
+ }
+
+ @Test
+ public void testOnChangeWithFullConfig() {
+ // Given
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.size.max", "5000");
+ properties.put("pinot.server.table.reload.status.cache.ttl.days", "15");
+ properties.put("some.other.config", "value");
+
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // When
+ cache.onChange(properties.keySet(), properties);
+
+ // Then
+ ServerReloadJobStatusCacheConfig config = cache.getCurrentConfig();
+ assertThat(config.getMaxSize()).isEqualTo(5000);
+ assertThat(config.getTtlDays()).isEqualTo(15);
+ }
+
+ @Test
+ public void testOnChangeWithPartialConfig() {
+ // Given
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.size.max", "7500");
+ properties.put("some.other.config", "value");
+
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // When
+ cache.onChange(properties.keySet(), properties);
+
+ // Then
+ ServerReloadJobStatusCacheConfig config = cache.getCurrentConfig();
+ assertThat(config.getMaxSize()).isEqualTo(7500);
+ // Verify default for unspecified config
+ assertThat(config.getTtlDays()).isEqualTo(30);
+ }
+
+ @Test
+ public void testOnChangeWithNoRelevantConfigs() {
+ // Given
+ Map<String, String> properties = new HashMap<>();
+ properties.put("some.other.config", "value");
+ properties.put("another.config", "123");
+
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // When
+ cache.onChange(properties.keySet(), properties);
+
+ // Then - Should keep defaults
+ ServerReloadJobStatusCacheConfig config = cache.getCurrentConfig();
+ assertThat(config.getMaxSize()).isEqualTo(10000);
+ assertThat(config.getTtlDays()).isEqualTo(30);
+ }
+
+ @Test
+ public void testOnChangeWithInvalidValues() {
+ // Given
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.size.max",
"invalid");
+
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+ ServerReloadJobStatusCacheConfig oldConfig = cache.getCurrentConfig();
+
+ // When - Invalid config should keep old cache
+ cache.onChange(properties.keySet(), properties);
+
+ // Then - Should keep old config due to error handling
+ ServerReloadJobStatusCacheConfig config = cache.getCurrentConfig();
+ assertThat(config).isSameAs(oldConfig);
+ assertThat(config.getMaxSize()).isEqualTo(10000);
+ }
+
+ @Test
+ public void testConfigUpdateOverwritesPrevious() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // Set initial config
+ Map<String, String> initialProperties = new HashMap<>();
+ initialProperties.put("pinot.server.table.reload.status.cache.size.max",
"8000");
+ initialProperties.put("pinot.server.table.reload.status.cache.ttl.days",
"20");
+ cache.onChange(initialProperties.keySet(), initialProperties);
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(8000);
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(20);
+
+ // When - Update with new config
+ Map<String, String> updatedProperties = new HashMap<>();
+ updatedProperties.put("pinot.server.table.reload.status.cache.size.max",
"12000");
+ updatedProperties.put("pinot.server.table.reload.status.cache.ttl.days",
"45");
+ cache.onChange(updatedProperties.keySet(), updatedProperties);
+
+ // Then
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(12000);
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(45);
+ }
+
+ @Test
+ public void testZookeeperConfigDeletionRevertsToDefaults() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // Set initial custom configs
+ Map<String, String> customProperties = new HashMap<>();
+ customProperties.put("pinot.server.table.reload.status.cache.size.max",
"15000");
+ customProperties.put("pinot.server.table.reload.status.cache.ttl.days",
"60");
+ cache.onChange(customProperties.keySet(), customProperties);
+
+ // Verify custom configs are applied
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(15000);
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(60);
+
+ // When - Simulate ZooKeeper config deletion with empty map
+ Map<String, String> emptyProperties = new HashMap<>();
+ cache.onChange(customProperties.keySet(), emptyProperties);
+
+ // Then - Verify all configs revert to defaults
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(10000);
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(30);
+ }
+
+ @Test
+ public void testBuildFromClusterConfigDirectly() {
+ // Given
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.size.max", "6000");
+ properties.put("pinot.server.table.reload.status.cache.ttl.days", "25");
+ properties.put("some.other.config", "value");
+
+ // When
+ ServerReloadJobStatusCacheConfig config =
+ ServerReloadJobStatusCache.buildFromClusterConfig(properties,
ServerReloadJobStatusCache.CONFIG_PREFIX);
+
+ // Then
+ assertThat(config.getMaxSize()).isEqualTo(6000);
+ assertThat(config.getTtlDays()).isEqualTo(25);
+ }
+
+ @Test
+ public void testCacheEntryMigrationOnRebuild() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ // Add some entries to cache
+ ReloadJobStatus status1 = cache.getOrCreate("job-1");
+ status1.incrementAndGetFailureCount();
+ ReloadJobStatus status2 = cache.getOrCreate("job-2");
+ status2.incrementAndGetFailureCount();
+ status2.incrementAndGetFailureCount();
+
+ // Verify initial state
+ assertThat(cache.getJobStatus("job-1").getFailureCount()).isEqualTo(1);
+ assertThat(cache.getJobStatus("job-2").getFailureCount()).isEqualTo(2);
+
+ // When - Trigger cache rebuild with config change
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.size.max", "5000");
+ properties.put("pinot.server.table.reload.status.cache.ttl.days", "15");
+ cache.onChange(properties.keySet(), properties);
+
+ // Then - Entries should be migrated to new cache
+ assertThat(cache.getJobStatus("job-1")).isNotNull();
+ assertThat(cache.getJobStatus("job-1").getFailureCount()).isEqualTo(1);
+ assertThat(cache.getJobStatus("job-2")).isNotNull();
+ assertThat(cache.getJobStatus("job-2").getFailureCount()).isEqualTo(2);
+
+ // Verify new config is applied
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(5000);
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(15);
+ }
+
+ @Test
+ public void testCacheRebuildWithDifferentSize() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(10000);
+
+ // When - Update only max size
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.size.max", "20000");
+ cache.onChange(properties.keySet(), properties);
+
+ // Then - Verify new size takes effect
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(20000);
+ // TTL should remain default
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(30);
+ }
+
+ @Test
+ public void testCacheRebuildWithDifferentTTL() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(30);
+
+ // When - Update only TTL
+ Map<String, String> properties = new HashMap<>();
+ properties.put("pinot.server.table.reload.status.cache.ttl.days", "45");
+ cache.onChange(properties.keySet(), properties);
+
+ // Then - Verify new TTL takes effect
+ assertThat(cache.getCurrentConfig().getTtlDays()).isEqualTo(45);
+ // Max size should remain default
+ assertThat(cache.getCurrentConfig().getMaxSize()).isEqualTo(10000);
+ }
+
+ @Test
+ public void testOnChangeSkipsRebuildWhenNoRelevantConfigsChanged() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ Map<String, String> initialProperties = new HashMap<>();
+ initialProperties.put("pinot.server.table.reload.status.cache.size.max",
"8000");
+ initialProperties.put("pinot.server.table.reload.status.cache.ttl.days",
"20");
+ cache.onChange(initialProperties.keySet(), initialProperties);
+
+ // Capture initial config instance
+ ServerReloadJobStatusCacheConfig configBeforeChange =
cache.getCurrentConfig();
+ assertThat(configBeforeChange.getMaxSize()).isEqualTo(8000);
+ assertThat(configBeforeChange.getTtlDays()).isEqualTo(20);
+
+ // When - Update with only non-reload-cache configs
+ Map<String, String> nonRelevantProperties = new HashMap<>();
+ nonRelevantProperties.put("some.other.config", "newValue");
+ nonRelevantProperties.put("another.config", "456");
+ // Include the previous reload cache configs to simulate cluster state
+ nonRelevantProperties.putAll(initialProperties);
+
+ cache.onChange(Set.of("some.other.config", "another.config"),
nonRelevantProperties);
+
+ // Then - Config instance should be the exact same object (no rebuild
occurred)
+ ServerReloadJobStatusCacheConfig configAfterChange =
cache.getCurrentConfig();
+ assertThat(configAfterChange).isSameAs(configBeforeChange);
+ }
+
+ @Test
+ public void testOnChangeRebuildsWhenRelevantConfigsChanged() {
+ // Given
+ ServerReloadJobStatusCache cache = new ServerReloadJobStatusCache();
+
+ Map<String, String> initialProperties = new HashMap<>();
+ initialProperties.put("pinot.server.table.reload.status.cache.size.max",
"8000");
+ initialProperties.put("pinot.server.table.reload.status.cache.ttl.days",
"20");
+ cache.onChange(initialProperties.keySet(), initialProperties);
+
+ ServerReloadJobStatusCacheConfig configBefore = cache.getCurrentConfig();
+ assertThat(configBefore.getMaxSize()).isEqualTo(8000);
+ assertThat(configBefore.getTtlDays()).isEqualTo(20);
+
+ // When - Update with reload cache configs changed
+ Map<String, String> updatedProperties = new HashMap<>();
+ updatedProperties.put("pinot.server.table.reload.status.cache.size.max",
"12000");
+ updatedProperties.put("pinot.server.table.reload.status.cache.ttl.days",
"40");
+ updatedProperties.put("some.other.config", "value");
+
+ cache.onChange(
+ Set.of("pinot.server.table.reload.status.cache.size.max",
"pinot.server.table.reload.status.cache.ttl.days"),
+ updatedProperties);
+
+ // Then - Config should be rebuilt with new values
+ ServerReloadJobStatusCacheConfig configAfter = cache.getCurrentConfig();
+ assertThat(configAfter).isNotSameAs(configBefore);
+ assertThat(configAfter.getMaxSize()).isEqualTo(12000);
+ assertThat(configAfter.getTtlDays()).isEqualTo(40);
+ }
+}
diff --git
a/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
b/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
index 2b019e3a917..f658b1bb56c 100644
---
a/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
+++
b/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
@@ -629,6 +629,10 @@ public abstract class BaseServerStarter implements
ServiceStartable {
LOGGER.info("Initializing reload job status cache");
_reloadJobStatusCache = new ServerReloadJobStatusCache();
+ // Register cache as cluster config listener for dynamic config updates
+
_clusterConfigChangeHandler.registerClusterConfigChangeListener(_reloadJobStatusCache);
+ LOGGER.info("Registered ServerReloadJobStatusCache as cluster config
listener");
+
// install default SSL context if necessary (even if not force-enabled
everywhere)
TlsConfig tlsDefaults = TlsUtils.extractTlsConfig(_serverConf,
Server.SERVER_TLS_PREFIX);
if (StringUtils.isNotBlank(tlsDefaults.getKeyStorePath()) ||
StringUtils.isNotBlank(
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]