title: Spring Cache refreshing obsolete values
body: <p>In a Spring-based application I have a service which performs the calculation of some <code>Index</code>. <code>Index</code> is relatively expensive to calculate (say, 1s) but relatively cheap to check for actuality (say, 20ms). Actual code does not matter, it goes along the following lines:</p>
  
  <pre><code>public Index getIndex() {
      return calculateIndex();
  }
  
  public Index calculateIndex() {
      // 1 second or more
  }
  
  public boolean isIndexActual(Index index) {
      // 20ms or less
  }
  </code></pre>
  
  <p>I'm using Spring Cache to cache the calculated index via <code>@Cacheable</code> annotation:</p>
  
  <pre><code>@Cacheable(cacheNames = CacheConfiguration.INDEX_CACHE_NAME)
  public Index getIndex() {
      return calculateIndex();
  }
  </code></pre>
  
  <p>We currently configure <code>GuavaCache</code> as cache implementation:</p>
  
  <pre><code>@Bean
  public Cache indexCache() {
      return new GuavaCache(INDEX_CACHE_NAME, CacheBuilder.newBuilder()
              .expireAfterWrite(indexCacheExpireAfterWriteSeconds, TimeUnit.SECONDS)
              .build());
  }
  
  @Bean
  public CacheManager indexCacheManager(List&lt;Cache&gt; caches) {
      SimpleCacheManager cacheManager = new SimpleCacheManager();
      cacheManager.setCaches(caches);
      return cacheManager;
  }
  </code></pre>
  
  <p>What I also need is to check if cached value is still actual and refresh it (ideally asynchronously) if it is not. So ideally it should go as follows:</p>
  
  <ul>
  <li>When <code>getIndex()</code> is called, Spring checks if there is a value in the cache.
  
  <ul>
  <li>If not, new value is loaded via <code>calculateIndex()</code> and stored in the cache</li>
  <li>If yes, the existing value is checked for actuality via <code>isIndexActual(...)</code>.
  
  <ul>
  <li>If old value is actual, it is returned.</li>
  <li>If old value is not actual, it is returned, but <em>removed from the cache and loading of the new value is triggered as well</em>.</li>
  </ul></li>
  </ul></li>
  </ul>
  
  <p>Basically I want to serve the value from the cache very fast (even if it is obsolete) but also trigger refreshing right away.</p>
  
  <p>What I've got working so far is checking for actuality and eviction:</p>
  
  <pre><code>@Cacheable(cacheNames = INDEX_CACHE_NAME)
  @CacheEvict(cacheNames = INDEX_CACHE_NAME, condition = "target.isObsolete(#result)")
  public Index getIndex() {
      return calculateIndex();
  }
  </code></pre>
  
  <p>This checks triggers eviction if the result is obsolete and returns the old value immediately even if it is the case. But this does not refresh the value in the cache.</p>
  
  <p>Is there a way to configure Spring Cache to actively refresh obsolete values after eviction?</p>
  
  <p><strong>Update</strong></p>
  
  <p>Here's a <a href="http://pastebin.com/ibstJe99" rel="noreferrer">MCVE</a>.</p>
  
  <pre><code>public static class Index {
  
      private final long timestamp;
  
      public Index(long timestamp) {
          this.timestamp = timestamp;
      }
  
      public long getTimestamp() {
          return timestamp;
      }
  }
  
  public interface IndexCalculator {
      public Index calculateIndex();
  
      public long getCurrentTimestamp();
  }
  
  @Service
  public static class IndexService {
      @Autowired
      private IndexCalculator indexCalculator;
  
      @Cacheable(cacheNames = "index")
      @CacheEvict(cacheNames = "index", condition = "target.isObsolete(#result)")
      public Index getIndex() {
          return indexCalculator.calculateIndex();
      }
  
      public boolean isObsolete(Index index) {
          long indexTimestamp = index.getTimestamp();
          long currentTimestamp = indexCalculator.getCurrentTimestamp();
          if (index == null || indexTimestamp &lt; currentTimestamp) {
              return true;
          } else {
              return false;
          }
      }
  }
  </code></pre>
  
  <p>Now the test:</p>
  
  <pre><code>@Test
  public void test() {
      final Index index100 = new Index(100);
      final Index index200 = new Index(200);
  
      when(indexCalculator.calculateIndex()).thenReturn(index100);
      when(indexCalculator.getCurrentTimestamp()).thenReturn(100L);
      assertThat(indexService.getIndex()).isSameAs(index100);
      verify(indexCalculator).calculateIndex();
      verify(indexCalculator).getCurrentTimestamp();
  
      when(indexCalculator.getCurrentTimestamp()).thenReturn(200L);
      when(indexCalculator.calculateIndex()).thenReturn(index200);
      assertThat(indexService.getIndex()).isSameAs(index100);
      verify(indexCalculator, times(2)).getCurrentTimestamp();
      // I'd like to see indexCalculator.calculateIndex() called after
      // indexService.getIndex() returns the old value but it does not happen
      // verify(indexCalculator, times(2)).calculateIndex();
  
  
      assertThat(indexService.getIndex()).isSameAs(index200);
      // Instead, indexCalculator.calculateIndex() os called on
      // the next call to indexService.getIndex()
      // I'd like to have it earlier
      verify(indexCalculator, times(2)).calculateIndex();
      verify(indexCalculator, times(3)).getCurrentTimestamp();
      verifyNoMoreInteractions(indexCalculator);
  }
  </code></pre>
  
  <p>I'd like to have the value refreshed shortly after it was evicted from the cache. At the moment it is refreshed on the next call of <code>getIndex()</code> first. If the value would have been refreshed right after eviction, this would save me 1s later on.</p>
  
  <p>I've tried <code>@CachePut</code>, but it also does not get me the desired effect. The value is refreshed, but the method is always executed, no matter what <code>condition</code> or <code>unless</code> are.</p>
  
  <p>The only way I see at the moment is to call <code>getIndex()</code> twice(second time async/non-blocking). But that's kind of stupid.</p>