Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data RedisTemplate, ttl is not working when setting a value

I want to set a ttl for my keys that are stored in Redis, and I have done that in the following way:

@Component
public class RedisBetgeniusMarketService implements BetgeniusMarketService {

    private static final int DEFAULT_EVENTS_LIFE_TIME = 240;

    @Value("${redis.events.lifetime}")
    private long eventsLifeTime = DEFAULT_EVENTS_LIFE_TIME;

    @Autowired
    private RedisTemplate<String, Market> marketTemplate;

    @Override
    public Market findOne(Integer fixtureId, Long marketId) {
        String key = buildKey(fixtureId, marketId);
        return marketTemplate.boundValueOps(key).get();
    }

    @Override
    public void save(Integer fixtureId, Market market) {
        String key = buildKey(fixtureId, market.getId());
        BoundValueOperations<String, Market> boundValueOperations = marketTemplate.boundValueOps(key);
        boundValueOperations.expire(eventsLifeTime, TimeUnit.MINUTES);
        boundValueOperations.set(market);
    }

    private String buildKey(Integer fixtureId, Long marketId) {
        return "market:" + fixtureId + ":" + marketId;
    }
}

But, when I am printing the ttl of the created key it's equal to -1.

Please, tell me what I am doing wrong.

The template bean is configured in the following way:

    @Bean
    public RedisTemplate<String, com.egalacoral.spark.betsync.entity.Market> marketTemplate(RedisConnectionFactory connectionFactory) {
        final RedisTemplate<String, com.egalacoral.spark.betsync.entity.Market> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(com.egalacoral.spark.betsync.entity.Market.class));
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    } 
like image 990
I. Domshchikov Avatar asked Jul 21 '16 11:07

I. Domshchikov


3 Answers

You need to call expire(…) and set(…) in a different order. The SET command removes any timeout that was previously applied:

From the documentation at http://redis.io/commands/set:

Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. Any previous time to live associated with the key is discarded on successful SET operation.

In your case you just need to switch the order of expire(…) and set(…) to set(…) and expire(…).

@Override
public void save(Integer fixtureId, Market market) {
    String key = buildKey(fixtureId, market.getId());
    BoundValueOperations<String, Market> boundValueOperations = marketTemplate.boundValueOps(key);

    boundValueOperations.set(market);
    boundValueOperations.expire(eventsLifeTime, TimeUnit.MINUTES);
}

Besides that, you could improve the code by setting the value and expiry in one call. ValueOperations (RedisOperations.opsForValue()) provides a set method that sets the key and timeout with the signature

void set(K key, V value, long timeout, TimeUnit unit);
like image 149
mp911de Avatar answered Oct 04 '22 03:10

mp911de


I have replace set() and the expire() methods and it's start working.

@Override
public void save(Integer fixtureId, Market market) {
    String key = buildKey(fixtureId, market.getId());
    BoundValueOperations<String, Market> boundValueOperations 
                                  = marketTemplate.boundValueOps(key);
    boundValueOperations.set(market);
    boundValueOperations.expire(eventsLifeTime, TimeUnit.MINUTES);
}
like image 20
I. Domshchikov Avatar answered Oct 04 '22 05:10

I. Domshchikov


You can try this also to expire a Key in Redis for a given specific time

redisTemplate.opsForValue().set(key, value, 1, TimeUnit.MINUTES);
like image 23
Vijai Avatar answered Oct 04 '22 04:10

Vijai