Expiry time @cacheable spring boot
Asked Answered
H

11

58

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")
Hhour answered 15/1, 2015 at 16:26 Comment(0)
E
38

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()));
  }

}
Elasticize answered 8/7, 2016 at 7:55 Comment(1)
Nice but this will evict all entries, old or new ones.Anatomist
C
16

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>
Connivance answered 15/1, 2015 at 16:34 Comment(2)
Spring boot doesn't have *xmlHhour
Oh yes there is! :) This is the default location for the EHCache configuration. Other caching libraries will presumably expect different locations.Connivance
K
15

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.

Koenraad answered 15/1, 2015 at 16:45 Comment(2)
Thank you. Finally I have added this in my application.yml: spring.resources.cache-periodHhour
Sorry, I don't see the link with your example. Sounds like totally unrelated to me. That property is to configure the cache period of the web resources.Koenraad
A
11

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.

Angeliaangelic answered 25/1, 2015 at 18:37 Comment(0)
F
10

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

spring.cache.cache-names=forecast
spring.cache.caffeine.spec=expireAfterWrite=60m
Fissile answered 12/7, 2018 at 16:34 Comment(2)
If I use caffeine cache.how to fill hibernate.cache.region.factory_class in spring.propertiesBiophysics
For others finding this answer, note that more information for these settings is in the Spring Boot Documentation.Sexology
K
4

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();
}
Kernan answered 19/10, 2020 at 18:47 Comment(2)
This should be considered as a workaround as this clears the whole cache (contrary to the notion of expiration which is different for each cached element).Lapillus
@JulienKronegg you can create such schedules for each cache separately. I agree that it muat be not the most convenient way though.Roister
C
3

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.

Cheka answered 1/1, 2022 at 7:8 Comment(0)
H
1

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

spring.cache.caffeine.spec=expireAfterAccess=300s
Halvorson answered 28/4, 2021 at 3:55 Comment(1)
If I use caffeine cache.how to fill hibernate.cache.region.factory_class in spring.propertiesBiophysics
H
0

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.

Hirza answered 30/11, 2023 at 9:9 Comment(0)
A
0

@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
Arnie answered 14/2 at 8:23 Comment(0)
C
0

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.

Chickamauga answered 22/2 at 14:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.