From cac82dfe777debb4918c757a343e21894092333a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 02:03:01 +0000 Subject: [PATCH 1/3] build(deps): bump com.github.ben-manes.caffeine:caffeine Bumps [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) from 2.9.3 to 3.0.0. - [Release notes](https://github.com/ben-manes/caffeine/releases) - [Commits](https://github.com/ben-manes/caffeine/compare/v2.9.3...v3.0.0) --- updated-dependencies: - dependency-name: com.github.ben-manes.caffeine:caffeine dependency-version: 3.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e7d1249728..24ace4f953 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 3.1.0 2.6 2.0.17 - 2.9.3 + 3.0.0 4.34.1 5.13.4 5.13.4 From b609abebcc0a6cc624df80ea69ace2d7867cb47c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:07:19 +0000 Subject: [PATCH 2/3] fix: update KubernetesFromConfigMapProcessor for Caffeine 3.x compatibility Replace async refresh() with synchronous put() and explicit invalidate() for keys removed from ConfigMap. This fixes a race condition introduced in Caffeine 3.x where asMap().get() returns null for expired entries during an in-flight async refresh, causing KubernetesFromConfigMapTest to fail intermittently. Changes: - Replace LoadingCache with Cache (CacheLoader no longer needed) - Remove expireAfterWrite (entries managed explicitly by scheduler) - Use put() to synchronously write ConfigMap data into cache - Use invalidate() to remove keys no longer present in ConfigMap - Remove ConfigMapGetterCacheLoader inner class Agent-Logs-Url: https://github.com/kubernetes-client/java/sessions/07e0048a-55b8-42c1-809c-ff20e3bd4837 Co-authored-by: brendandburns <5751682+brendandburns@users.noreply.github.com> --- .../KubernetesFromConfigMapProcessor.java | 44 +++++-------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java b/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java index 142d7528c2..95b1a6be51 100644 --- a/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java +++ b/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java @@ -12,9 +12,8 @@ */ package io.kubernetes.client.spring.extended.manifests; -import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.spring.extended.manifests.annotation.FromConfigMap; import io.kubernetes.client.spring.extended.manifests.config.KubernetesManifestsProperties; @@ -24,9 +23,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -80,15 +76,7 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw ConfigMapGetter configMapGetter = getOrCreateConfigMapGetter(fromConfigMapAnnotation, applicationContext); - LoadingCache configMapDataCache = - Caffeine.newBuilder() - .expireAfterWrite(manifestsProperties.getRefreshInterval()) - .build( - new ConfigMapGetterCacheLoader( - () -> { - return configMapGetter.get( - fromConfigMapAnnotation.namespace(), fromConfigMapAnnotation.name()); - })); + Cache configMapDataCache = Caffeine.newBuilder().build(); fullyRefreshCache(configMapGetter, fromConfigMapAnnotation, configMapDataCache); configMapKeyRefresher.scheduleAtFixedRate( () -> { @@ -106,14 +94,20 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw private static void fullyRefreshCache( ConfigMapGetter configMapGetter, FromConfigMap fromConfigMapAnnotation, - LoadingCache configMapDataCache) { + Cache configMapDataCache) { V1ConfigMap configMap = configMapGetter.get(fromConfigMapAnnotation.namespace(), fromConfigMapAnnotation.name()); if (configMap == null || configMap.getData() == null) { + configMapDataCache.invalidateAll(); return; } // TODO: make the cache data refreshment atomic - configMap.getData().keySet().stream().forEach(key -> configMapDataCache.refresh(key)); + Map newData = configMap.getData(); + newData.forEach(configMapDataCache::put); + configMapDataCache.asMap().keySet().stream() + .filter(key -> !newData.containsKey(key)) + .collect(java.util.stream.Collectors.toList()) + .forEach(configMapDataCache::invalidate); } private ConfigMapGetter getOrCreateConfigMapGetter( @@ -144,22 +138,4 @@ private ConfigMapGetter getOrCreateConfigMapGetter( public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } - - static class ConfigMapGetterCacheLoader implements CacheLoader { - - ConfigMapGetterCacheLoader(Supplier configMapSupplier) { - this.configMapSupplier = configMapSupplier; - } - - private final Supplier configMapSupplier; - - @Override - public @Nullable String load(@NonNull String key) throws Exception { - V1ConfigMap configMap = this.configMapSupplier.get(); - if (configMap == null || configMap.getData() == null) { - return null; - } - return configMap.getData().get(key); - } - } } From 66dd19cfd90755a098555da6389425a45e1c3b87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:12:34 +0000 Subject: [PATCH 3/3] fix: clean up imports and use Set.copyOf for snapshot in fullyRefreshCache Agent-Logs-Url: https://github.com/kubernetes-client/java/sessions/07e0048a-55b8-42c1-809c-ff20e3bd4837 Co-authored-by: brendandburns <5751682+brendandburns@users.noreply.github.com> --- .../extended/manifests/KubernetesFromConfigMapProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java b/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java index 95b1a6be51..5312cd04d4 100644 --- a/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java +++ b/spring/src/main/java/io/kubernetes/client/spring/extended/manifests/KubernetesFromConfigMapProcessor.java @@ -20,6 +20,7 @@ import io.kubernetes.client.spring.extended.manifests.configmaps.ConfigMapGetter; import java.lang.reflect.Field; import java.util.Map; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -104,9 +105,8 @@ private static void fullyRefreshCache( // TODO: make the cache data refreshment atomic Map newData = configMap.getData(); newData.forEach(configMapDataCache::put); - configMapDataCache.asMap().keySet().stream() + Set.copyOf(configMapDataCache.asMap().keySet()).stream() .filter(key -> !newData.containsKey(key)) - .collect(java.util.stream.Collectors.toList()) .forEach(configMapDataCache::invalidate); }