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]

Reply via email to