From 697f9ef797310b45be201dfa581fc616b712ef61 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Wed, 27 May 2026 10:30:09 +0200 Subject: [PATCH 1/2] replace deprecated JedisCluster with RedisClusterClient, support tls mode --- .../eclipse/openvsx/cache/CacheConfig.java | 36 ++++++-------- .../JedisClusterBucket4jConfiguration.java | 22 +++++---- .../bucket4j/JedisClusterCacheListener.java | 14 +++--- .../bucket4j/JedisClusterCacheManager.java | 16 +++---- .../bucket4j/JedisClusterCacheResolver.java | 18 ++++--- .../jedis/JedisClusterChannelListener.java | 10 ++-- .../openvsx/cache/jedis/JedisUtil.java | 48 +++++++++++++++++++ .../openvsx/ratelimit/UsageStatsService.java | 14 +++--- .../cache/RateLimitCacheService.java | 16 +++---- .../ratelimit/config/RateLimitConfig.java | 34 +++++-------- .../scanning/GitleaksRulesService.java | 35 +++++++------- .../openvsx/settings/SettingsService.java | 20 ++++---- 12 files changed, 162 insertions(+), 121 deletions(-) create mode 100644 server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisUtil.java diff --git a/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java b/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java index dfb09c759..0b09b73b5 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/CacheConfig.java @@ -18,8 +18,8 @@ import com.github.benmanes.caffeine.jcache.CacheManagerImpl; import com.github.benmanes.caffeine.jcache.configuration.CaffeineConfiguration; import com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider; -import io.micrometer.common.util.StringUtils; import org.eclipse.openvsx.adapter.ExtensionQueryResult; +import org.eclipse.openvsx.cache.jedis.JedisUtil; import org.eclipse.openvsx.entities.ExtensionVersion; import org.eclipse.openvsx.json.ExtensionJson; import org.eclipse.openvsx.json.NamespaceDetailsJson; @@ -42,17 +42,13 @@ import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.*; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; +import redis.clients.jedis.*; import java.net.URI; import java.time.Duration; import java.util.List; import java.util.OptionalLong; import java.util.Properties; -import java.util.stream.Collectors; import static org.eclipse.openvsx.cache.CacheService.*; @@ -144,30 +140,26 @@ public Cache settingCache( @Bean @ConditionalOnExpression("${bucket4j.enabled:false} && '${bucket4j.cache-to-use:}' == 'redis-jedis'") - public JedisPool jedisPool(RedisProperties properties) { + public RedisClient redisClient(RedisProperties properties) { logger.info("Configure 'redis-jedis' bucket4j rate-limiting cache"); - return new JedisPool(properties.getHost(), properties.getPort(), properties.getUsername(), properties.getPassword()); + var builder = RedisClient.builder(); + + builder.hostAndPort(properties.getHost(), properties.getPort()); + builder.clientConfig(JedisUtil.getClientConfig(properties)); + + return builder.build(); } @Bean @ConditionalOnExpression("${bucket4j.enabled:false} && '${bucket4j.cache-to-use:}' == 'redis-cluster-jedis'") - public JedisCluster jedisCluster(RedisProperties properties) { + public RedisClusterClient redisClusterClient(RedisProperties properties) { logger.info("Configure 'redis-cluster-jedis' bucket4j rate-limiting cache"); - var configBuilder = DefaultJedisClientConfig.builder(); - var username = properties.getUsername(); - if(StringUtils.isNotEmpty(username)) { - configBuilder.user(username); - } - var password = properties.getPassword(); - if(StringUtils.isNotEmpty(password)) { - configBuilder.password(password); - } - var nodes = properties.getCluster().getNodes().stream() - .map(HostAndPort::from) - .collect(Collectors.toSet()); + var builder = RedisClusterClient.builder(); + builder.nodes(JedisUtil.getNodes(properties)); + builder.clientConfig(JedisUtil.getClientConfig(properties)); - return new JedisCluster(nodes, configBuilder.build()); + return builder.build(); } @Bean diff --git a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterBucket4jConfiguration.java b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterBucket4jConfiguration.java index 90bf27c81..afa16eb45 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterBucket4jConfiguration.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterBucket4jConfiguration.java @@ -27,40 +27,46 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; @Configuration @ConditionalOnBucket4jEnabled @ConditionalOnSynchronousPropertyCondition @ConditionalOnClass(JedisBasedProxyManager.JedisBasedProxyManagerBuilder.class) -@ConditionalOnBean(JedisCluster.class) +@ConditionalOnBean(RedisClusterClient.class) @ConditionalOnCache("redis-cluster-jedis") public class JedisClusterBucket4jConfiguration { - public final JedisCluster jedisCluster; + public final RedisClusterClient redisClusterClient; private final String configCacheName; - public JedisClusterBucket4jConfiguration(JedisCluster jedisCluster, Bucket4JBootProperties properties) { - this.jedisCluster = jedisCluster; + public JedisClusterBucket4jConfiguration(RedisClusterClient redisClusterClient, Bucket4JBootProperties properties) { + this.redisClusterClient = redisClusterClient; this.configCacheName = properties.getFilterConfigCacheName(); } @Bean @ConditionalOnMissingBean(SyncCacheResolver.class) public SyncCacheResolver bucket4RedisResolver() { - return new JedisClusterCacheResolver(jedisCluster); + return new JedisClusterCacheResolver(redisClusterClient); } @Bean @ConditionalOnMissingBean(CacheManager.class) @ConditionalOnFilterConfigCacheEnabled public CacheManager configCacheManager() { - return new JedisClusterCacheManager<>(jedisCluster, configCacheName, Bucket4JConfiguration.class); + return new JedisClusterCacheManager<>(redisClusterClient, configCacheName, Bucket4JConfiguration.class); } @Bean @ConditionalOnFilterConfigCacheEnabled public JedisClusterCacheListener configCacheListener(ApplicationEventPublisher eventPublisher) { - return new JedisClusterCacheListener<>(jedisCluster, configCacheName, String.class, Bucket4JConfiguration.class, eventPublisher); + return new JedisClusterCacheListener<>( + redisClusterClient, + configCacheName, + String.class, + Bucket4JConfiguration.class, + eventPublisher + ); } } diff --git a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheListener.java b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheListener.java index 27223ea42..8360c883e 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheListener.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheListener.java @@ -20,8 +20,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; -import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.RedisClusterClient; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -33,20 +33,20 @@ public class JedisClusterCacheListener extends JedisPubSub { private static final Logger LOGGER = LoggerFactory.getLogger(JedisClusterCacheListener.class); - private final JedisCluster jedisCluster; + private final RedisClusterClient redisClusterClient; private final ObjectMapper objectMapper = new ObjectMapper(); private final String updateChannel; private final JavaType deserializeType; private final ApplicationEventPublisher eventPublisher; /** - * @param jedisCluster The cluster to use for listening/publishing events + * @param redisClusterClient The cluster to use for listening/publishing events * @param cacheName The name of the cache. This is used as prefix for the event channels * @param keyType The type of the key. This is required for parsing events and should match the K of this class. * @param valueType The type of the value. This is required for parsing events and should match the V of this class. */ - public JedisClusterCacheListener(JedisCluster jedisCluster, String cacheName, Class keyType, Class valueType, ApplicationEventPublisher eventPublisher) { - this.jedisCluster = jedisCluster; + public JedisClusterCacheListener(RedisClusterClient redisClusterClient, String cacheName, Class keyType, Class valueType, ApplicationEventPublisher eventPublisher) { + this.redisClusterClient = redisClusterClient; this.updateChannel = cacheName.concat(":update"); this.deserializeType = objectMapper.getTypeFactory().constructParametricType(CacheUpdateEvent.class, keyType, valueType); this.eventPublisher = eventPublisher; @@ -66,7 +66,7 @@ public void subscribe() { // This is done in a different thread since subscribe is a blocking call. resetTask = executorService.schedule(()-> reconnectBackoffTimeMillis.set(1000), 10000, TimeUnit.MILLISECONDS); - jedisCluster.subscribe(this, updateChannel); + redisClusterClient.subscribe(this, updateChannel); } catch (Exception e) { LOGGER.error("Failed to connect the Jedis subscriber, attempting to reconnect in {} seconds. " + "Exception was: {}", (reconnectBackoffTimeMillis.get() /1000), e.getMessage()); @@ -93,7 +93,7 @@ public void subscribe() { } private boolean isUp() { - return jedisCluster.ping().equals("PONG"); + return redisClusterClient.ping().equals("PONG"); } @Override diff --git a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheManager.java b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheManager.java index 1202e60cb..021ea9645 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheManager.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheManager.java @@ -18,25 +18,25 @@ import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheUpdateEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; public class JedisClusterCacheManager implements CacheManager { private static final Logger LOGGER = LoggerFactory.getLogger(JedisClusterCacheManager.class); - private final JedisCluster cluster; + private final RedisClusterClient redisClusterClient; private final String cacheName; private final Class valueType; private final ObjectMapper objectMapper; private final String updateChannel; /** - * @param cluster The JedisCluster to use for reading/writing data to the cache + * @param redisClusterClient The RedisClusterClient to use for reading/writing data to the cache * @param cacheName The name of the cache. * @param valueType The type of the data. This is required for parsing and should always match the V of this class. */ - public JedisClusterCacheManager(JedisCluster cluster, String cacheName, Class valueType) { - this.cluster = cluster; + public JedisClusterCacheManager(RedisClusterClient redisClusterClient, String cacheName, Class valueType) { + this.redisClusterClient = redisClusterClient; this.cacheName = cacheName; this.valueType = valueType; @@ -48,7 +48,7 @@ public JedisClusterCacheManager(JedisCluster cluster, String cacheName, Class @Override public V getValue(K key) { try { - String serializedValue = cluster.hget(cacheName, objectMapper.writeValueAsString(key)); + String serializedValue = redisClusterClient.hget(cacheName, objectMapper.writeValueAsString(key)); return serializedValue != null ? objectMapper.readValue(serializedValue, this.valueType) : null; } catch (JsonProcessingException e) { LOGGER.warn("Exception occurred while retrieving key '{}' from cache '{}'. Message: {}", key, cacheName, e.getMessage()); @@ -63,12 +63,12 @@ public void setValue(K key, V value) { String serializedKey = objectMapper.writeValueAsString(key); String serializedValue = objectMapper.writeValueAsString(value); - cluster.hset(this.cacheName, serializedKey, serializedValue); + redisClusterClient.hset(this.cacheName, serializedKey, serializedValue); //publish an update event if the key already existed if(oldValue != null){ CacheUpdateEvent updateEvent = new CacheUpdateEvent<>(key, oldValue, value); - cluster.publish(this.updateChannel, objectMapper.writeValueAsString(updateEvent)); + redisClusterClient.publish(this.updateChannel, objectMapper.writeValueAsString(updateEvent)); } } catch (JsonProcessingException e) { LOGGER.warn("Exception occurred while setting key '{}' in cache '{}'. Message: {}", key, cacheName, e.getMessage()); diff --git a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheResolver.java b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheResolver.java index 9a24ba5d6..73e7caa55 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheResolver.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/bucket4j/JedisClusterCacheResolver.java @@ -16,8 +16,9 @@ import com.giffing.bucket4j.spring.boot.starter.config.cache.SyncCacheResolver; import io.github.bucket4j.distributed.ExpirationAfterWriteStrategy; import io.github.bucket4j.distributed.proxy.AbstractProxyManager; +import io.github.bucket4j.distributed.proxy.ClientSideConfig; import io.github.bucket4j.redis.jedis.cas.JedisBasedProxyManager; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; import java.time.Duration; @@ -25,10 +26,10 @@ public class JedisClusterCacheResolver extends AbstractCacheResolverTemplate implements SyncCacheResolver { - private final JedisCluster jedisCluster; + private final RedisClusterClient redisClusterClient; - public JedisClusterCacheResolver(JedisCluster jedisCluster) { - this.jedisCluster = jedisCluster; + public JedisClusterCacheResolver(RedisClusterClient redisClusterClient) { + this.redisClusterClient = redisClusterClient; } @Override @@ -43,8 +44,13 @@ public byte[] castStringToCacheKey(String key) { @Override public AbstractProxyManager getProxyManager(String cacheName) { - return JedisBasedProxyManager.builderFor(jedisCluster) - .withExpirationStrategy(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10))) + var clientSideConfig = + ClientSideConfig.getDefault().withExpirationAfterWriteStrategy( + ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10)) + ); + + return JedisBasedProxyManager.builderFor(redisClusterClient) + .withClientSideConfig(clientSideConfig) .build(); } } diff --git a/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisClusterChannelListener.java b/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisClusterChannelListener.java index c609dd01d..c0c4c2079 100644 --- a/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisClusterChannelListener.java +++ b/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisClusterChannelListener.java @@ -15,8 +15,8 @@ import io.micrometer.core.instrument.util.NamedThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.RedisClusterClient; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledFuture; @@ -26,7 +26,7 @@ public abstract class JedisClusterChannelListener extends JedisPubSub { private final Logger logger = LoggerFactory.getLogger(JedisClusterChannelListener.class); - private final JedisCluster jedisCluster; + private final RedisClusterClient redisClusterClient; private final String channelName; private final String listenerName; @@ -34,8 +34,8 @@ public abstract class JedisClusterChannelListener extends JedisPubSub { private volatile Thread subscriberThread; private volatile boolean running = true; - public JedisClusterChannelListener(JedisCluster jedisCluster, String channelName, String listenerName) { - this.jedisCluster = jedisCluster; + public JedisClusterChannelListener(RedisClusterClient redisClusterClient, String channelName, String listenerName) { + this.redisClusterClient = redisClusterClient; this.channelName = channelName; this.listenerName = listenerName; } @@ -68,7 +68,7 @@ private void subscribeLoop() { try { resetTask = executor.schedule(() -> backoffMs.set(1000), 10, TimeUnit.SECONDS); logger.debug("Subscribing to redis channel {}", channelName); - jedisCluster.subscribe(this, channelName); + redisClusterClient.subscribe(this, channelName); } catch (Exception e) { if (!running) break; logger.warn( diff --git a/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisUtil.java b/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisUtil.java new file mode 100644 index 000000000..eba4deabd --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/cache/jedis/JedisUtil.java @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.openvsx.cache.jedis; + +import io.micrometer.common.util.StringUtils; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisClientConfig; + +import java.util.Set; +import java.util.stream.Collectors; + +public class JedisUtil { + + private JedisUtil() {} + + public static JedisClientConfig getClientConfig(RedisProperties properties) { + var configBuilder = DefaultJedisClientConfig.builder(); + var username = properties.getUsername(); + if (StringUtils.isNotEmpty(username)) { + configBuilder.user(username); + } + var password = properties.getPassword(); + if (StringUtils.isNotEmpty(password)) { + configBuilder.password(password); + } + + configBuilder.ssl(properties.getSsl().isEnabled()); + return configBuilder.build(); + } + + public static Set getNodes(RedisProperties properties) { + return properties.getCluster().getNodes().stream() + .map(HostAndPort::from) + .collect(Collectors.toSet()); + } +} diff --git a/server/src/main/java/org/eclipse/openvsx/ratelimit/UsageStatsService.java b/server/src/main/java/org/eclipse/openvsx/ratelimit/UsageStatsService.java index e03d4308e..dd44380ea 100644 --- a/server/src/main/java/org/eclipse/openvsx/ratelimit/UsageStatsService.java +++ b/server/src/main/java/org/eclipse/openvsx/ratelimit/UsageStatsService.java @@ -26,7 +26,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -50,18 +50,18 @@ public class UsageStatsService { private final RepositoryService repositories; private final CustomerService customerService; private final Cache usageCache; - private final JedisCluster jedisCluster; + private final RedisClusterClient redisClusterClient; public UsageStatsService( RepositoryService repositories, CustomerService customerService, Cache usageCache, - JedisCluster jedisCluster + RedisClusterClient redisClusterClient ) { this.repositories = repositories; this.customerService = customerService; this.usageCache = usageCache; - this.jedisCluster = jedisCluster; + this.redisClusterClient = redisClusterClient; } public void incrementUsage(Customer customer) { @@ -81,7 +81,7 @@ public void syncDistributedUsageData() { if (v != null) { var value = (Long) v; if (value > 0) { - jedisCluster.hincrBy(USAGE_DATA_KEY, key.toString(), value.intValue()); + redisClusterClient.hincrBy(USAGE_DATA_KEY, key.toString(), value.intValue()); } } return null; @@ -96,7 +96,7 @@ public void persistUsageStats() { ScanResult> results; do { - results = jedisCluster.hscan(USAGE_DATA_KEY, cursor); + results = redisClusterClient.hscan(USAGE_DATA_KEY, cursor); for (var result : results.getResult()) { var key = result.getKey(); @@ -128,7 +128,7 @@ public void persistUsageStats() { } } } finally { - jedisCluster.hdel(USAGE_DATA_KEY, key); + redisClusterClient.hdel(USAGE_DATA_KEY, key); } } } diff --git a/server/src/main/java/org/eclipse/openvsx/ratelimit/cache/RateLimitCacheService.java b/server/src/main/java/org/eclipse/openvsx/ratelimit/cache/RateLimitCacheService.java index 762c2fbe5..1404bf20d 100644 --- a/server/src/main/java/org/eclipse/openvsx/ratelimit/cache/RateLimitCacheService.java +++ b/server/src/main/java/org/eclipse/openvsx/ratelimit/cache/RateLimitCacheService.java @@ -23,8 +23,8 @@ import org.springframework.cache.CacheManager; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.RedisClusterClient; @Service @ConditionalOnBean(RateLimitConfig.class) @@ -40,19 +40,19 @@ public class RateLimitCacheService extends JedisPubSub { private final Logger logger = LoggerFactory.getLogger(RateLimitCacheService.class); - private final JedisCluster jedisCluster; + private final RedisClusterClient redisClusterClient; private final CacheManager cacheManager; private final ConfigCacheUpdateListener configCacheListener; private final ApplicationEventPublisher eventPublisher; public RateLimitCacheService( - JedisCluster jedisCluster, + RedisClusterClient redisClusterClient, @Qualifier(CACHE_MANAGER) CacheManager cacheManager, ApplicationEventPublisher eventPublisher ) { - this.jedisCluster = jedisCluster; + this.redisClusterClient = redisClusterClient; this.cacheManager = cacheManager; - this.configCacheListener = new ConfigCacheUpdateListener(jedisCluster); + this.configCacheListener = new ConfigCacheUpdateListener(redisClusterClient); this.eventPublisher = eventPublisher; } @@ -68,7 +68,7 @@ public void shutdown() { public void publishConfigUpdate(String cacheName, String key) { logger.debug("Publish update rate-limit config {}: {}", cacheName, key); - jedisCluster.publish(CONFIG_UPDATE_CHANNEL, cacheName + ":" + key); + redisClusterClient.publish(CONFIG_UPDATE_CHANNEL, cacheName + ":" + key); } public void evictCustomerCache() { @@ -120,8 +120,8 @@ public void evictTokens(String[] tokens) { } private class ConfigCacheUpdateListener extends JedisClusterChannelListener { - public ConfigCacheUpdateListener(JedisCluster jedisCluster) { - super(jedisCluster, CONFIG_UPDATE_CHANNEL, "RateLimitConfig"); + public ConfigCacheUpdateListener(RedisClusterClient redisClusterClient) { + super(redisClusterClient, CONFIG_UPDATE_CHANNEL, "RateLimitConfig"); } @Override diff --git a/server/src/main/java/org/eclipse/openvsx/ratelimit/config/RateLimitConfig.java b/server/src/main/java/org/eclipse/openvsx/ratelimit/config/RateLimitConfig.java index 64615420e..57ecac824 100644 --- a/server/src/main/java/org/eclipse/openvsx/ratelimit/config/RateLimitConfig.java +++ b/server/src/main/java/org/eclipse/openvsx/ratelimit/config/RateLimitConfig.java @@ -19,7 +19,7 @@ import io.github.bucket4j.distributed.proxy.ClientSideConfig; import io.github.bucket4j.distributed.proxy.ProxyManager; import io.github.bucket4j.redis.jedis.cas.JedisBasedProxyManager; -import io.micrometer.common.util.StringUtils; +import org.eclipse.openvsx.cache.jedis.JedisUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -36,12 +36,9 @@ import org.springframework.expression.spel.SpelCompilerMode; import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; -import redis.clients.jedis.DefaultJedisClientConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; import java.time.Duration; -import java.util.stream.Collectors; import static org.eclipse.openvsx.ratelimit.cache.RateLimitCacheService.*; @@ -62,23 +59,14 @@ public ExpressionParser expressionParser() { } @Bean - public JedisCluster jedisCluster(RedisProperties properties) { + public RedisClusterClient redisClusterClient(RedisProperties properties) { logger.info("Configure jedis-cluster rate-limiting cache"); - var configBuilder = DefaultJedisClientConfig.builder(); - var username = properties.getUsername(); - if(StringUtils.isNotEmpty(username)) { - configBuilder.user(username); - } - var password = properties.getPassword(); - if(StringUtils.isNotEmpty(password)) { - configBuilder.password(password); - } - - var nodes = properties.getCluster().getNodes().stream() - .map(HostAndPort::from) - .collect(Collectors.toSet()); - - return new JedisCluster(nodes, configBuilder.build()); + + var builder = RedisClusterClient.builder(); + builder.nodes(JedisUtil.getNodes(properties)); + builder.clientConfig(JedisUtil.getClientConfig(properties)); + + return builder.build(); } @Bean @@ -151,8 +139,8 @@ public CacheManager rateLimitCacheManager( @Bean @ConditionalOnMissingBean(ProxyManager.class) - public ProxyManager jedisBasedProxyManager(JedisCluster jedisCluster) { - return JedisBasedProxyManager.builderFor(jedisCluster) + public ProxyManager redisBasedProxyManager(RedisClusterClient redisClusterClient) { + return JedisBasedProxyManager.builderFor(redisClusterClient) .withClientSideConfig( ClientSideConfig .getDefault() diff --git a/server/src/main/java/org/eclipse/openvsx/scanning/GitleaksRulesService.java b/server/src/main/java/org/eclipse/openvsx/scanning/GitleaksRulesService.java index eb81821ba..d82eb618c 100644 --- a/server/src/main/java/org/eclipse/openvsx/scanning/GitleaksRulesService.java +++ b/server/src/main/java/org/eclipse/openvsx/scanning/GitleaksRulesService.java @@ -24,11 +24,12 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; -import redis.clients.jedis.JedisCluster; import jakarta.annotation.Nullable; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import redis.clients.jedis.RedisClusterClient; + import java.io.File; import java.io.IOException; import java.net.URI; @@ -68,7 +69,7 @@ public class GitleaksRulesService implements JobRequestHandler detectorFactoryProvider; - private final JedisCluster jedisCluster; + private final RedisClusterClient redisClusterClient; private final RulesUpdateChannelListener rulesUpdateChannelListener; // Path to generated rules file @@ -77,14 +78,14 @@ public class GitleaksRulesService implements JobRequestHandler detectorFactoryProvider, - @Nullable JedisCluster jedisCluster + @Nullable RedisClusterClient redisClusterClient ) { this.config = config; this.detectorFactoryProvider = detectorFactoryProvider; - this.jedisCluster = jedisCluster; + this.redisClusterClient = redisClusterClient; - if (jedisCluster != null) { - this.rulesUpdateChannelListener = new RulesUpdateChannelListener(jedisCluster); + if (redisClusterClient != null) { + this.rulesUpdateChannelListener = new RulesUpdateChannelListener(redisClusterClient); logger.debug("GitleaksRulesService initialized with Redis sync"); } else { this.rulesUpdateChannelListener = null; @@ -201,7 +202,7 @@ public void run(HandlerJobRequest jobRequest) throws Exception { } // Sync to Redis and notify other pods - if (jedisCluster != null) { + if (redisClusterClient != null) { String rulesContent = readRulesFile(); if (rulesContent != null) { boolean synced = storeAndPublishRules(rulesContent); @@ -221,8 +222,8 @@ public void run(HandlerJobRequest jobRequest) throws Exception { } private class RulesUpdateChannelListener extends JedisClusterChannelListener { - RulesUpdateChannelListener(JedisCluster jedisCluster) { - super(jedisCluster, RULES_UPDATE_CHANNEL, "GitleaksRules"); + RulesUpdateChannelListener(RedisClusterClient redisClusterClient) { + super(redisClusterClient, RULES_UPDATE_CHANNEL, "GitleaksRules"); } @Override @@ -238,13 +239,13 @@ public void onMessage(String channel, String message) { * Store rules in Redis and notify other pods. */ public boolean storeAndPublishRules(String rulesContent) { - if (jedisCluster == null) return false; + if (redisClusterClient == null) return false; try { String version = String.valueOf(System.currentTimeMillis()); - jedisCluster.set(RULES_KEY, rulesContent); - jedisCluster.set(RULES_VERSION_KEY, version); - jedisCluster.publish(RULES_UPDATE_CHANNEL, version); + redisClusterClient.set(RULES_KEY, rulesContent); + redisClusterClient.set(RULES_VERSION_KEY, version); + redisClusterClient.publish(RULES_UPDATE_CHANNEL, version); logger.debug("Stored gitleaks rules in Redis (version: {}, size: {} bytes)", version, rulesContent.length()); return true; @@ -255,10 +256,10 @@ public boolean storeAndPublishRules(String rulesContent) { } private void loadRulesFromRedisIfNewer() { - if (jedisCluster == null) return; + if (redisClusterClient == null) return; try { - String redisVersion = jedisCluster.get(RULES_VERSION_KEY); + String redisVersion = redisClusterClient.get(RULES_VERSION_KEY); if (redisVersion == null) { logger.debug("No gitleaks rules in Redis yet"); return; @@ -283,10 +284,10 @@ private void loadRulesFromRedisIfNewer() { } private void loadRulesFromRedis() { - if (jedisCluster == null) return; + if (redisClusterClient == null) return; try { - String rulesContent = jedisCluster.get(RULES_KEY); + String rulesContent = redisClusterClient.get(RULES_KEY); if (rulesContent == null || rulesContent.isEmpty()) { logger.warn("No rules content found in Redis"); return; diff --git a/server/src/main/java/org/eclipse/openvsx/settings/SettingsService.java b/server/src/main/java/org/eclipse/openvsx/settings/SettingsService.java index 2f4f49975..9677b097c 100644 --- a/server/src/main/java/org/eclipse/openvsx/settings/SettingsService.java +++ b/server/src/main/java/org/eclipse/openvsx/settings/SettingsService.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; import java.util.ArrayList; @@ -33,16 +33,16 @@ public class SettingsService { private final Logger logger = LoggerFactory.getLogger(SettingsService.class); - private final @Nullable JedisCluster jedisCluster; + private final @Nullable RedisClusterClient redisClusterClient; private final SettingsUpdateListener settingsUpdateListener; private final SettingsCache cache; - public SettingsService(@Nullable JedisCluster jedisCluster, SettingsCache cache) { - this.jedisCluster = jedisCluster; + public SettingsService(@Nullable RedisClusterClient redisClusterClient, SettingsCache cache) { + this.redisClusterClient = redisClusterClient; this.cache = cache; - if (jedisCluster != null) { - settingsUpdateListener = new SettingsUpdateListener(jedisCluster); + if (redisClusterClient != null) { + settingsUpdateListener = new SettingsUpdateListener(redisClusterClient); logger.info("SettingsService initialized with Redis update listener"); } else { settingsUpdateListener = null; @@ -84,16 +84,16 @@ public String updateFromJson(SettingsJson newSettings) { } private void publishSettingsUpdate() { - if (jedisCluster != null) { + if (redisClusterClient != null) { logger.debug("Publish settings update"); String version = String.valueOf(System.currentTimeMillis()); - jedisCluster.publish(SETTINGS_UPDATE_CHANNEL, version); + redisClusterClient.publish(SETTINGS_UPDATE_CHANNEL, version); } } private class SettingsUpdateListener extends JedisClusterChannelListener { - SettingsUpdateListener(JedisCluster jedisCluster) { - super(jedisCluster, SETTINGS_UPDATE_CHANNEL, "SettingsUpdate"); + SettingsUpdateListener(RedisClusterClient redisClusterClient) { + super(redisClusterClient, SETTINGS_UPDATE_CHANNEL, "SettingsUpdate"); } @Override From d547e18ec2facf5f8d919ff522d60c46ac066d01 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Wed, 27 May 2026 10:43:13 +0200 Subject: [PATCH 2/2] fix unit test --- .../eclipse/openvsx/ratelimit/RateLimitIntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/test/java/org/eclipse/openvsx/ratelimit/RateLimitIntegrationTest.java b/server/src/test/java/org/eclipse/openvsx/ratelimit/RateLimitIntegrationTest.java index f7a9470ac..10d457520 100644 --- a/server/src/test/java/org/eclipse/openvsx/ratelimit/RateLimitIntegrationTest.java +++ b/server/src/test/java/org/eclipse/openvsx/ratelimit/RateLimitIntegrationTest.java @@ -24,7 +24,7 @@ import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.bean.override.mockito.MockitoBean; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.RedisClusterClient; import java.net.URI; import java.time.Duration; @@ -46,7 +46,7 @@ class RateLimitIntegrationTest { TestRestTemplate restTemplate; @MockitoBean - JedisCluster jedisCluster; + RedisClusterClient redisClusterClient; @MockitoBean ProxyManager proxyManager;