3

I am searching a way to set the TTL with spring annotation.

I tried

@CacheEvict(allEntries = true, value = { "mycache" })
@Scheduled(fixedDelay = 5000)

And putting @EnableScheduling on my Application.java with no success.

I also tried @RedisHash(timeToLive=2000) on the class with and without @TimeToLive(unit = TimeUnit.SECONDS) on method.

Then I tried to put @EnableRedisRepositories(keyspaceConfiguration = UserKeySpaceConfiguration.class) on my class

public class UserKeySpaceConfiguration extends KeyspaceConfiguration {

  /**
   * {@inheritDoc}
   *
   * @see org.springframework.data.redis.core.convert.KeyspaceConfiguration#getKeyspaceSettings(java.lang.Class)
   */
  @Override
  public KeyspaceSettings getKeyspaceSettings(final Class<?> type) {
    final KeyspaceSettings keyspaceSettings = new KeyspaceSettings(type, "user-keyspace");
    keyspaceSettings.setTimeToLive(172800L);
    return keyspaceSettings;
  }

  /**
   * {@inheritDoc}
   * @see org.springframework.data.redis.core.convert.KeyspaceConfiguration#hasSettingsFor(java.lang.Class)
   */
  @Override
  public boolean hasSettingsFor(final Class<?> type) {
    return true;
  }

}

All this method don't work. When I check Redis if my keys have TTL, I always have -1.

Any idea on how to proceed ?

Thanks.

Youri C.
  • 133
  • 1
  • 12
  • did you try `spring.cache.redis.time-to-live=600000` ??? – Yogen Rai Jul 10 '18 at 17:35
  • I retry and it works perfectly maybe I had a bad syntax or a very short delay. But with this solution the TTL is global to all keys or I want to put different TTL on different keys – Youri C. Jul 11 '18 at 08:11

2 Answers2

9

Well after a week of search I found a solution.

To have different TTL on different keys you have to create your own cache manager.

So in your Application.java add your custom cache manager.

@SpringBootApplication
@EnableSwagger2
@EnableCaching
public class Application extends SpringBootServletInitializer {

  public static void main(final String[] args) throws Exception {
    SpringApplication.run(Application.class, args);
  }

  @Primary
  @Bean
  public RedisCacheManager cacheManager(final RedisConnectionFactory connectionFactory) {
    final RedisCacheWriter redisCacheWriter = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);
    final SerializationPair<Object> valueSerializationPair = RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());
    final RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
    final RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, cacheConfiguration);
    return redisCacheManager;
  }

  @Bean(name = "pickleCacheManager")
  public RedisCacheManager pickleCacheManager(final RedisConnectionFactory connectionFactory) {
    final RedisCacheWriter redisCacheWriter = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);
    final SerializationPair<Object> valueSerializationPair = RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());
    RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
    cacheConfiguration = cacheConfiguration.entryTtl(Duration.ofSeconds(120));
    final RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, cacheConfiguration);
    return redisCacheManager;
  }

  @Bean(name = "userCacheManager")
  public RedisCacheManager userCacheManager(final RedisConnectionFactory connectionFactory) {
    final RedisCacheWriter redisCacheWriter = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);
    final SerializationPair<Object> valueSerializationPair = RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());
    RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
    cacheConfiguration = cacheConfiguration.entryTtl(Duration.ofSeconds(172800));
    final RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, cacheConfiguration);
    return redisCacheManager;
  }

}

To make the difference between your cache, you have the attribut name with annotation @Bean.

You need to have a @Primary @Bean or your application will crash. In my case my primary juste return the cache without change.

So in this custom cache I just add a TTL with

cacheConfiguration = cacheConfiguration.entryTtl(Duration.ofSeconds(120));

And when you use your cache on a method you just need to specify your cache like so:

@Cacheable(value = "value", key = "#key", cacheManager = "yourCacheName")

In my case

@Cacheable(value = "pickle", key = "#pickleId", cacheManager = "pickleCacheManager")
Pickle findFirstById(String pickleId);

Your cacheManager in @Cacheable is your name in @Bean.

Youri C.
  • 133
  • 1
  • 12
  • But doesn't every key in pickleCacheManager have a TTL of 120? How do you change that for single keys? – mhuelfen Aug 12 '22 at 13:41
0

You need to update

@CacheEvict(allEntries = true, value = { "mycache" })

to

@CacheEvict(allEntries = true, cacheNames = { "mycache" })

It can refer to this answer on StackOverflow.

Yogen Rai
  • 2,961
  • 3
  • 25
  • 37
  • What is not say in this answer is that do I need to `@EnableScheduling` on my Application ? And can I do this : `@CacheEvict(allEntries = true, cacheNames = { "pickle" }) @Cacheable(value = "pickle", key = "#pickleId") @Scheduled(fixedDelay = 5000) Pickle findFirstById(String pickleId);` I want to put TTL when you search object. – Youri C. Jul 11 '18 at 07:56
  • When I tried this solution on my method with `@Cacheable` `@CacheEvict` and `@Scheduled`, my object is not add to the cache – Youri C. Jul 11 '18 at 08:14