How can I update a redis value without affecting the remaining TTL?
Asked Answered
V

7

41

Is it possible to SET redis keys without removing their existing ttl? The only way I know of at the present time is to find out the ttl and do a SETEX but that seems less accurate.

Viosterol answered 20/2, 2014 at 3:13 Comment(0)
C
37

The KEEPTTL option will be added to SET in redis>=6.0

https://redis.io/commands/set

https://github.com/antirez/redis/pull/6679

The SET command supports a set of options that modify its behavior:

EX seconds -- Set the specified expire time, in seconds.
PX milliseconds -- Set the specified expire time, in milliseconds.
NX -- Only set the key if it does not already exist.
XX -- Only set the key if it already exist.
(!) KEEPTTL -- Retain the time to live associated with the key.
Cordon answered 17/1, 2020 at 16:23 Comment(0)
E
21

According to Redis documentation, the SET command removes the TTL because the key is overwritten.

However you can use the EVAL command to evaluate a Lua script to do it automatically for you.

The script bellow checks for the TTL value of a key, if the value is positive it calls SETEX with the new value and using the remaining TTL.

local ttl = redis.call('ttl', ARGV[1]) if ttl > 0 then return redis.call('SETEX', ARGV[1], ttl, ARGV[2]) end

Example:

> set key 123

OK

> expire key 120

(integer) 1

... after some seconds

> ttl key

(integer) 97

> eval "local ttl = redis.call('ttl', ARGV[1]) if ttl > 0 then return redis.call('SETEX', ARGV[1], ttl, ARGV[2]) end" 0 key 987

OK

> ttl key

96

> get key

"987"

Enneahedron answered 20/2, 2014 at 4:1 Comment(0)
P
17

Maybe the INCR, INCRBY, DECR, etc. can help you. They don't modify the TTL.

> setex test 3600 13
OK

> incr test
(integer) 14

> ttl test
(integer) 3554

http://redis.io/commands/INCR

Paulino answered 6/1, 2015 at 17:32 Comment(1)
this worked perfectly for me as I was dealing with integer values.Shipment
C
2

It is possible to change the value without affecting TTL on it's key by changing value bits one by one according to new value by using SETBIT.

Disadvantage of this approach however is obviously performance impact, especially if value is quite big.

NOTE: It is advisable to execute this in transaction (multi exec) block

Maintaining TTL by ourselves by

  • Fetching current TTL

  • Set new value

  • Restoring TTL after setting value

    is obviously not advisable due to unknown durability of the commands executed.

Another alternative is to use List as data type and after adding new value to the list with LPUSH use LTRIM to maintain size of list to single element. This wont change TTL on the key.

Cookery answered 2/6, 2017 at 7:41 Comment(0)
T
0

Here's a function to check the existing TTL and use it if needed.

expire arguments 0 - use existing expire time, >0 - set a new expire time, undefined - no expire time.

    /**
       * update an item. preserve ttl or set a new one
       * @param {object} handle the redis handle
       * @param {string} key the key
       * @param {*} content the content - if an object it'll get stringified
       * @param {number||null} expire if a number > 0 its an expire time, 0 
means keep existing ttl, undefined means no expiry
       * @return {Promise}
       */
      ns.updateItem = function (handle , key , content,expire) {

        // first we have to get the expiry time if needed
        return (expire === 0 ? handle.ttl(key) : Promise.resolve (expire))
        .then (function (e) {

          // deal with errors retrieving the ttl (-1 no expiry, -2 no existing record)
          var ttl = e > 0 ? e :  undefined;

          // stingify the data if needed
          var data = typeof content === "object" ? JSON.stringify(content) : content;

          // set and apply ttl if needed
          return ttl ? handle.set (key, data , "EX", ttl) : handle.set (key,data);
        });
      };
Tahmosh answered 19/4, 2017 at 9:59 Comment(0)
K
0

There is one way to get the remaining TTL from Redis.

Maintaining TTL in Redis :

  1. Get current TTL
  2. Set new value
  3. Restoring TTL after setting value

Example:

// This function helps to get the  Remaining TTL from the redis.
        const  getRemainingTTL=(key)=> {  
            return new Promise((resolve,reject)=>{
                redisClient.TTL(key,(err,value)=>{
                    if(err)reject(err);
                    resolve(value);
                });
            });
        };
     let remainingTTL=await getRemainingTTL(otpSetKey);
     console.log('remainingTTL',remainingTTL);

     redisClient.set(key,newValue,'EX',exTime ); // set agin
Kinsley answered 30/9, 2021 at 5:42 Comment(0)
P
-1

For some reason for me this kind of function did not work:

 redisSender.set('tenMinWaitTime', avg, 'KEEPTTL')

instead I needed to write this:

 redisSender.set('tenMinWaitTime', avg, { KEEPTTL: true })

documentation can be found here: https://www.npmjs.com/package//redis

Prothallus answered 25/3, 2022 at 9:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.