29

Is it possible to schedule spring cache eviction to everyday at midnight?

I've read Springs Cache Docs and found nothing about scheduled cache eviction.

I need to evict cache daily and recache it in case there were some changes outside my application.

default locale
  • 13,035
  • 13
  • 56
  • 62
Philippe Gioseffi
  • 1,488
  • 3
  • 24
  • 41

7 Answers7

41

Try to use @Scheduled Example:

@Scheduled(fixedRate = ONE_DAY)
@CacheEvict(value = { CACHE_NAME })
public void clearCache() {  
    log.debug("Cache '{}' cleared.", CACHE);    
}

You can also use cron expression with @Scheduled.

  • How the Scheduled annotation bind itself to CacheEvict annotation to understand what it is supposed to do? – Philippe Gioseffi Mar 09 '17 at 06:50
  • '@Scheduled' invoke method clearCache a specified time. Cache is cleaned because the method is triggered by CacheEvict. Remember to include configuration @EnableScheduling in class configuration. – Oleksandr Bondarchuk Mar 09 '17 at 07:04
  • 1
    It didn't work for me, i hate to split it into 2 components and 2 different methods. I had to create another component (ClearCacheScheduler) with method using only Scheduled annotation, which then called clearCache() method annotated with CacheEvict of my service component. – Celebes Jun 18 '18 at 16:27
  • 2
    This don't work. Scheduled and CacheEvict have to be in different classes/methods. – voliveira89 Oct 31 '18 at 17:19
  • 13
    Don't forget `@EnableScheduling` in the Application class. – Drakes Oct 13 '19 at 10:26
  • Any workarounds if Sonar argues on empty method: SonarLint: Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation. – Zon Feb 20 '20 at 12:23
  • 2
    @Zon Just add a comment, for ex. "//nothing to do" – Oleksandr Bondarchuk Feb 25 '20 at 13:39
  • Have checked at SpringBoot 2.5.5 - it's doesn't work! Take @fafl solution (https://stackoverflow.com/a/64071461/548473) – Grigory Kislin Oct 03 '21 at 16:20
  • 2
    @Zon log statement? – java-addict301 Feb 02 '22 at 19:00
13

If you use @Cacheable on methods with parameters, you should NEVER forget the allEntries=true annotation property on the @CacheEvict, otherwise your call will only evict the key parameter you give to the clearCache() method, which is nothing => you will not evict anything from the cache.

Johannes Di
  • 151
  • 1
  • 4
6

Maybe not the most elegant solution, but @CacheEvict was not working, so I directly went for the CacheManager.

This code clears a cache called foo via scheduler:

class MyClass {

    @Autowired CacheManager cacheManager;

    @Cacheable(value = "foo")
    public Int expensiveCalculation(String bar) {
        ...
    }

    @Scheduled(fixedRate = 60 * 1000);
    public void clearCache() {
        cacheManager.getCache("foo").clear();
    }
}
fafl
  • 7,222
  • 3
  • 27
  • 50
3

I know this question is old, but I found a better solution that worked for me. Maybe that will help others.

So, it is indeed possible to make a scheduled cache eviction. Here is what I did in my case.

Both annotations @Scheduled and @CacheEvict do not seem to work together. You must thus split apart the scheduling method and the cache eviction method. But since the whole mechanism is based on proxies, only external calls to public methods of your class will trigger the cache eviction. This because internal calls between to methods of the same class do not go through the Spring proxy.

I managed to fixed it the same way as Celebes (see comments), but with an improvement to avoid two components.

@Component
class MyClass
{

    @Autowired
    MyClass proxiedThis; // store your component inside its Spring proxy.

    // A cron expression to define every day at midnight
    @Scheduled(cron ="0 0 * * *")
    public void cacheEvictionScheduler()
    {
        proxiedThis.clearCache();
    }

    @CacheEvict(value = { CACHE_NAME })
    public void clearCache()
    {
        // intentionally left blank. Or add some trace info.
    }    
}
bugsbuRny
  • 51
  • 4
  • Don't confuse everyone. `@Scheduled` and `@CacheEvict` work together. For inner-bean calls you can also use `applicationContext.getBean(MyClass.class).clearCache()`. – sjngm Oct 16 '18 at 13:40
  • 1
    Well it seems it did not work for at least two people here. Which version of spring boot do you work with? (or spring) – bugsbuRny Oct 17 '18 at 23:03
  • I use Spring Boot 2.0.5. I don't think that it's related to the version since `@Scheduled` and `@CacheEvict` are around for quite some time. If it's not working then there's usually some other side effect from another corner. You can try with a [very simple project](https://spring.io/guides/gs/spring-boot/) and add a method with the two annotations plus `@EnableScheduling` and `@EnableCaching`. – sjngm Oct 18 '18 at 10:21
  • for me original answer started to work when my configuration class stopped extending CachingConfigurerSupport and became a regular configuration class (I had the method in my @Configuration class) – eis Nov 13 '19 at 14:34
3

Please follow the below code.change cron expression accordingly. I have set it for 3 minutes

  1. Create a class.

  2. Use the below method inside the class.

    class A 
    {
    @Autowired CacheManager cacheManager;
    
    @Scheduled(cron ="0 */3 * ? * *")
        public void cacheEvictionScheduler()
        {
             logger.info("inside scheduler start");
            //clearCache();
             evictAllCaches();
            logger.info("inside scheduler end");
        }
    
    public void evictAllCaches() {
             logger.info("inside clearcache");
            cacheManager.getCacheNames().stream()
              .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
        }
    }
    
David Buck
  • 3,752
  • 35
  • 31
  • 35
samit tiwary
  • 99
  • 1
  • 3
1

Spring cache framework is event driven i.e. @Cacheable or @CacheEvict will be triggered only when respective methods are invoked.

However you can leverage the underlying cache provider (remember the Spring cache framework is just an abstraction and does not provide a cache solution by itself) to invalidate the cache by itself. For instance EhCache has a property viz. timeToLiveSeconds which dictates the time till the cache be active. But this won't re-populate the cache for you unless the @Cacheable annotated method is invoked.

So for cache eviction and re-population at particular time (say midnight as mentioned) consider implementing a background scheduled service in Spring which will trigger the cache eviction and re-population as desired. The expected behavior is not provided out-of-box.

Hope this helps.

Bond - Java Bond
  • 3,972
  • 6
  • 36
  • 59
1

Use annotations @Scheduled with a cron expression and @CacheEvict with allEntries = true like this:

/*
* This clears the entire cache called "myCache" everyday, 
* at 00.00 (am) in the time zone of the server.
*/
@Scheduled(cron = "0 0 0 * * ?")
@CacheEvict(value = "myCache", allEntries = true)
public void clearMyCache() {}

If you want to add logic before clearing the cache you can do so in the method body:

/*
* This clears the entire cache called "myCache" everyday, 
* at 00.00 (am) in the time zone of the server.
*/
@Scheduled(cron = "0 0 0 * * ?")
@CacheEvict(value = "myCache", allEntries = true)
public void clearMyCache() {

    // Add logic here
    log.debug("Clearing myCache now");

}

The CacheEvict hapens after your code runs and only if it doesn't throw any exceptions. You can change that by adding "beforeInvocation = true" in which case it evicts the cache first, then runs your code.

JavaDevSweden
  • 2,154
  • 2
  • 18
  • 29