0

I have spring micro-service application which using redis-server for cache store. Using RedisCacheManager Api. In this we have option to set "setDefaultExpiration". Because of that rediscachemanager calculating expiry from first access of annotated method(@cacheable).

I want to calculate expiry time from last access of cacheable method not from first access. Google library has given direct method to achive this: In CacheBuilder we have method called expireAfterAccess CacheBuilder API

We can use this when we want to use google gauva server. But in my application I have to use redis server for cache because of my centralised cache server requirement. I checked RedisCacheManager class and didn't find a way to achive this. How I can achieve this feature in redis-cache-server. Below code for creating RedisCacheManager bean:

@Bean
RedisCacheManager cacheManager() {
    final RedisCacheManager redisCacheManager = new RedisCacheManager(
            redisTemplate());
    redisCacheManager.setUsePrefix(true);
    redisCacheManager.setDefaultExpiration(redisExpireTime);


    return redisCacheManager;
}
Prakash Jha
  • 1
  • 3
  • 6
  • That's a Redis setting: https://redis.io/topics/lru-cache – mp911de Feb 09 '17 at 12:31
  • @mp911de I think we need to configure some functinality in spring framework. Because evict request for cached data coming from application. – Prakash Jha Feb 10 '17 at 06:45
  • Redis supports only unconditional expiry after time. There's no relation to expiry after access. Spring Data Redis lets you defining an expiry that is set after write. (Expiry after write) – mp911de Feb 10 '17 at 08:13
  • @mp911de Yes, I know redis support only "expiry after write". But I am looking for solution of "expiry after access" in spring data Redis. Thank you for looking into it. – Prakash Jha Feb 10 '17 at 11:16

1 Answers1

0

I solved this problem by customizing the cacheResolver , but it seems inefficient.

public class MyCacheResolver extends SimpleCacheResolver {

@Autowired
private RedisTemplate<Object, Object> template;

public CustomCacheResolver(CacheManager cacheManager) {
    super(cacheManager);
}

@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
    if (context.getOperation() instanceof CacheableOperation) {
        DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
        CacheableOperation op = (CacheableOperation) context.getOperation();
        String[] ps = discover.getParameterNames(context.getMethod());
        EvaluationContext ctx = new StandardEvaluationContext();
        for (int i = 0; i < ps.length; i++) {
            ctx.setVariable(ps[i], context.getArgs()[i]);
        }
        ExpressionParser parser = new SpelExpressionParser();
        String redisKey = parser.parseExpression(op.getKey()).getValue(ctx, String.class);
        String prefix = getCacheNames(context).iterator().next();
        long time = template.getExpire(prefix + ":" + redisKey);
        if (time > 0) {
            template.expire(prefix + ":" + redisKey, 300L, TimeUnit.SECONDS);
        }
    }
    return super.resolveCaches(context);
}
}

in my case ,every cache hit will automatically refresh the cache ttl to 300 seconds. then inject the cacheResolver to configuration class,

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean("customCacheResolver")
    @Override
    public CacheResolver cacheResolver() {
        return new CustomCacheResolver(cacheManager());
    }

 @Bean
 public RedisCacheManager cacheManager() {
     //define your cacheManager here
 }

}

i hope it's clear,English is not my native language.

kajibu
  • 174
  • 1
  • 7