user3322664
user3322664

Reputation:

Expiry time @cacheable spring boot

I have implemented a cache and now I want to add an expiry time.

How can I set an expiry time in spring boot with @Cacheable?

This is a code snippet:

@Cacheable(value="forecast",unless="#result == null")

Upvotes: 60

Views: 124006

Answers (11)

user2989397
user2989397

Reputation: 311

I ran into this and needed a way for volume public traffic to get cached content fast, and not cause a big buildup with cache eviction. I created two entry points to the service method that fetches the data, as so:

        @Cacheable(value="document")
public Document findByIdCacheable(Integer id) throws ResourceNotFoundException {
    return fetchDocument(id);
}
    
@CachePut(value="document")
public Document findById(Integer id) throws ResourceNotFoundException {
    return fetchDocument(id, versionId, privileged);
}

@Transactional(readOnly=true)
private Document fetchDocument(Integer id) throws ResourceNotFoundException {
  ... perform the work here
}

You can then provide a scheduled task to call the method with the @CachePut annotation on a periodic basis to update the cache entry without evicting it. Under heavy front end load from the public, I find that evicting cache entries can cause, under some implementations, a massive queue up of incoming transaction threads if the back end of the service takes more than a few seconds to build the entry. I find this can help prevent that, as well as provide an entry point to bypass cache by a controller method for administrative purposes.

Upvotes: 0

Yash Kakrecha
Yash Kakrecha

Reputation: 55

@Cacheable does not support expire time. But if you are using redis then you can use time-to-live and set the time.

For example :

spring.cache.redis.time-to-live=60m

Upvotes: 0

Ferhat C
Ferhat C

Reputation: 11

You can solve it with a LocalDateTime object. For example:

@Cacheable(value="forecast", key = "#date.toString()")
public void forecast(LocalDate date){
    //
}
public void call(){
    forecast(LocalDate.now());
}

Cache will expire after 1 day.

Positive aspect - it does not require a scheduled job.

Negative aspect - old data remains cached.

Upvotes: 1

Atum
Atum

Reputation: 1301

I use life hacking like this:

@Configuration
@EnableCaching
@EnableScheduling
public class CachingConfig {

  public static final String GAMES = "GAMES";

  @Bean
  public CacheManager cacheManager() {
    ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(GAMES);
    return cacheManager;
  }

  @CacheEvict(allEntries = true, value = {GAMES})
  @Scheduled(fixedDelay = 10 * 60 * 1000 ,  initialDelay = 500)
  public void reportCacheEvict() {
    System.out.println("Flush Cache " + dateFormat.format(new Date()));
  }

}

Upvotes: 40

Amritansh
Amritansh

Reputation: 321

Found this Spring cache: Set expiry time to a cache entry.

It uses the spring-boot-starter-cache dependency and works as expected . You can configure the expiry time for cached objects as well as the max number of cached values.

Upvotes: 4

Bu Saeed
Bu Saeed

Reputation: 1337

If you are using Caffeine than you can add the following line in your application.properties file:

spring.cache.caffeine.spec=expireAfterAccess=300s

Upvotes: 1

talhature
talhature

Reputation: 2165

You can achieve this kind of eviction strategy by making use of @Scheduled annotation. It is possible to schedule with a fixedRate or even with a cron expression.

@Autowired
CacheManager cacheManager;

public void evictAllCaches() {
        cacheManager.getCacheNames().stream()
          .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
}

@Scheduled(fixedRate = 6000)
public void evictAllcachesAtIntervals() {
        evictAllCaches();
}

Upvotes: 5

slartidan
slartidan

Reputation: 21586

I use caffeine-caching, with this configuration for a 60 minute expiration:

spring.cache.cache-names=forecast
spring.cache.caffeine.spec=expireAfterWrite=60m

Upvotes: 10

Steve
Steve

Reputation: 9480

Note that this answer uses ehcache, which is one of supported Spring Boot cache managers, and arguably one of the most popular.

First you need to add to pom.xml:

<!-- Spring Framework Caching Support -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

In src/main/resources/ehcache.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <defaultCache eternal="true" maxElementsInMemory="100" overflowToDisk="false" />
    <cache name="forecast" 
           maxElementsInMemory="1000" 
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           overflowToDisk="false"
           memoryStoreEvictionPolicy="LRU" />
</ehcache>

Upvotes: 16

Sameer Shah
Sameer Shah

Reputation: 1083

You cannot specify expiry time with @cacheable notation, since @cacheable does not provide any such configurable option.

However different caching vendors providing spring caching have provided this feature through their own configurations. For example NCache / TayzGrid allows you to create different cache regions with configurable expiration time.

If you have implemented your own cache, you will need to define a way to specify expiration in you cache provider and will also need to incorporate expiration logic in your solution.

Upvotes: 11

Stephane Nicoll
Stephane Nicoll

Reputation: 33111

From the reference documentation

Directly through your cache provider. The cache abstraction is… well, an abstraction not a cache implementation. The solution you are using might support various data policies and different topologies which other solutions do not (take for example the JDK ConcurrentHashMap) - exposing that in the cache abstraction would be useless simply because there would no backing support. Such functionality should be controlled directly through the backing cache, when configuring it or through its native API.

Upvotes: 15

Related Questions