Custom TTL for Spring data Redis Cache

Upasana | October 01, 2020 | 2 min read | 2,978 views


Spring Boot 2.2+ provides options to customize Redis Cache using RedisCacheManagerBuilderCustomizer enabling us to set custom value for TTL (time-to-live/expiry) for each of the configured cache.

At the time of writing this article, Spring Boot 2.3.4.RELEASE does not allow configuring TTL value for each individual cache through application.yml, so we need to use RedisCacheManagerBuilderCustomizer if we want to configure different timeout for each individual cache.

Redis Setup

You can easily setup Redis on Ubuntu machine using the below command

Ubuntu 18.04 LTS & 20.04 LTS
$ sudo apt update
$ sudo apt install redis-server

Check redis service status using the below systemctl command:

$ sudo systemctl status redis-server.service

If you are using Mac, then homebrew can be used to quickly install Redis server.

Mac using homebrew
$ brew install redis

On windows, you can get pre-compiled executable of redis from here redislab or here microsoftarchive redis 3.2

Gradle setup

We will be using Spring Boot 2.3.4.RELEASE for this tutorial with dependencies on Spring Data Redis. You can find about Spring Data Redis project here Spring Boot Features

build.gradle
implementation("org.springframework.boot:spring-boot-starter-data-redis")

Spring Boot Redis configuration

We need to configure Spring data redis cache in application.yml for properties hostname, port number and cache names.

application.yml
spring.redis.host: localhost
spring.redis.port: 6379
spring.cache.cache-names: cache1, cache2
spring.cache.redis.time-to-live: 600000   (1)
1 redis.time-to-live allows setting up TTL for the all caches to same value.

The only caveat with this setting (spring.cache.redis.time-to-live) is that you cannot specify custom TTL value for individual cache.

Customize TTL for individual cache in Redis

We will create a custom configuration to create a Bean of type RedisCacheManagerBuilderCustomizer to allow RedisCacheManager configuration. RedisCacheConfiguration allows a method named entryTtl(Duration) that allows us to set custom value for TTL for a given Cache.

RedisConfig.java
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class RedisConfig {

    @Bean
    RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
        return (builder) -> {
            Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
            configurationMap.put("cache1", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(20)));  (1)
            configurationMap.put("cache2", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(2)));     (2)
            builder.withInitialCacheConfigurations(configurationMap);
        };
    }

}
1 cache1 will have expiry of 20 seconds from time of creation.
2 cache2 will have expiry of 2 hours from time of creation (time-to-live).

Kotlin equivalent of the same configuration is this:

RedisConfig.kt
@Configuration
class RedisConfig {

    @Bean
    fun redisCacheManagerBuilderCustomizer() = RedisCacheManagerBuilderCustomizer { builder ->
        val configurationMap = HashMap<String, RedisCacheConfiguration>()
        configurationMap["cache1"] = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(20))
        configurationMap["cache2"] = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(2))
        builder.withInitialCacheConfigurations(configurationMap)
    }
}

Now we are good to use Redis cache within our controllers.

Test controller with Redis cache
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisTestController {

    @RequestMapping("/hello/{name}")
    @Cacheable("cache1")
    public String hello(@PathVariable String name) throws InterruptedException {
        Thread.sleep(3000);
        return "Hello " + name;
    }
}

If we call GET /hello/carvia, the very first call should take around 3 seconds, subsequent calls should be instant since method invocation results will be cached for next 20 seconds.

That’s all.


Top articles in this category:
  1. Redis rate limiter in Spring Boot
  2. Custom banner in spring boot
  3. Setting a Random Port in Spring Boot Application at startup
  4. Prevent Lost Updates in Database Transaction using Spring Hibernate
  5. Disable SSL validation in Spring RestTemplate
  6. N+1 problem in Hibernate & Spring Data JPA
  7. Elasticsearch with Spring Boot + Spring Data

Recommended books for interview preparation:

Find more on this topic: