Description
LocalResponseCacheGatewayFilterFactory appears to recreate and register a new Caffeine cache every time Gateway routes are refreshed.
When Spring Cloud Gateway is used with Eureka DiscoveryClient, routes may be refreshed periodically. In my case, this happens every 30 seconds from the following thread:
DiscoveryClient-CacheRefreshExecutor
Each refresh causes LocalResponseCacheGatewayFilterFactory.apply() to be invoked again.
The following code creates and registers a new cache every time:
Caffeine caffeine = LocalResponseCacheUtils.createCaffeine(cacheProperties);
String cacheName = config.getRouteId() + "-cache";
caffeineCacheManager.registerCustomCache(
cacheName,
caffeine.build()
);
This produces the following log every 30 seconds:
13:32:25.740 [DiscoveryClient-CacheRefreshExecutor-%d]
INFO LocalResponseCacheUtils - Initializing Caffeine
13:32:55.779 [DiscoveryClient-CacheRefreshExecutor-%d]
INFO LocalResponseCacheUtils - Initializing Caffeine
Expected behavior
The cache associated with a route should be reused when the route is rebuilt and the cache configuration has not changed.
A route refresh should not recreate the underlying Caffeine cache or remove existing cached responses.
Actual behavior
apply() creates a new Caffeine cache and calls registerCustomCache() again using the same cache name:
String cacheName = config.getRouteId() + "-cache";
Depending on the behavior of CaffeineCacheManager.registerCustomCache(), this may replace the existing cache and clear all cached entries.
Even when the cache is not replaced, a new unused Caffeine cache instance is still created during every route refresh.
Steps to reproduce
- Configure Spring Cloud Gateway with Eureka DiscoveryClient.
- Enable the local response cache filter.
- Configure a route with
LocalResponseCache.
- Start the gateway.
- Wait for Eureka registry refresh.
- Observe that
LocalResponseCacheUtils.createCaffeine() is invoked repeatedly.
Example configuration:
spring:
cloud:
gateway:
filter:
local-response-cache:
enabled: true
eureka:
client:
registry-fetch-interval-seconds: 30
Suggested fix
Before creating a new cache, check whether a cache with the same name already exists:
String cacheName = config.getRouteId() + "-cache";
Cache routeCache = caffeineCacheManager.getCache(cacheName);
if (routeCache == null) {
Caffeine caffeine =
LocalResponseCacheUtils.createCaffeine(cacheProperties);
caffeineCacheManager.registerCustomCache(
cacheName,
caffeine.build()
);
routeCache = caffeineCacheManager.getCache(cacheName);
}
A more complete solution could recreate the cache only when the route cache configuration, such as TTL or size, has actually changed.
Environment
Spring Cloud Gateway version: (v3.4.4)
Spring Boot version: (v3.4.4)
Spring Cloud version: (v3.4.4)
Java version: 21
Discovery client: Eureka
Additional context
Route refresh itself is expected behavior. The concern is that the filter factory is not idempotent and creates a new cache whenever the route definition is rebuilt.
Description
LocalResponseCacheGatewayFilterFactoryappears to recreate and register a new Caffeine cache every time Gateway routes are refreshed.When Spring Cloud Gateway is used with Eureka DiscoveryClient, routes may be refreshed periodically. In my case, this happens every 30 seconds from the following thread:
Each refresh causes
LocalResponseCacheGatewayFilterFactory.apply()to be invoked again.The following code creates and registers a new cache every time:
This produces the following log every 30 seconds:
Expected behavior
The cache associated with a route should be reused when the route is rebuilt and the cache configuration has not changed.
A route refresh should not recreate the underlying Caffeine cache or remove existing cached responses.
Actual behavior
apply()creates a new Caffeine cache and callsregisterCustomCache()again using the same cache name:Depending on the behavior of
CaffeineCacheManager.registerCustomCache(), this may replace the existing cache and clear all cached entries.Even when the cache is not replaced, a new unused Caffeine cache instance is still created during every route refresh.
Steps to reproduce
LocalResponseCache.LocalResponseCacheUtils.createCaffeine()is invoked repeatedly.Example configuration:
Suggested fix
Before creating a new cache, check whether a cache with the same name already exists:
A more complete solution could recreate the cache only when the route cache configuration, such as TTL or size, has actually changed.
Environment
Additional context
Route refresh itself is expected behavior. The concern is that the filter factory is not idempotent and creates a new cache whenever the route definition is rebuilt.