I miss a command which gets me a value and also extends the TTL with one call. I think that could save a lot of requests in some use cases.

Example:

1 redis> GETEX nonexisting 100 (nil)

2 redis> SET mykey "Hello" OK

3 redis> GETEX mykey 100

"Hello"

3 redis would also run this command: EXPIRE mykey 100

Is there a chance that you might add this command?

Comment From: badboy

You can just use GET + EXPIRE in a transaction.

Comment From: ipapapa

@badboy Get and touch is a common pattern and in terms of API parity I do not understand why SETEX is performed without a transaction and GET + EXPIRE requires a transaction. Can we revisit this? Also asked in #1652.

Comment From: fsck-mount

Is this available ?

Comment From: HcgRandon

This should be implemented get and ex is a common use case.

Comment From: fsck-mount

@HcgRandon I feel the same.

Comment From: ipapapa

@HcgRandon How can I set the expire in a GET: https://redis.io/commands/get in a single operation/call? If we can do that it would save a lot of extra requests to the server. That is the point of SET with EX, NX and XX flags.

Comment From: badboy

There's no command for that implemented currently. You can use MULTI; GET x; EXPIRE x 1000; EXEC or use a Lua script to do the same.

Comment From: ipapapa

Right, the transaction will maintain the operation being a single unit but will not decrease the number of operations (rather increase and increase the latencies as well). Lua scripting is a potential solution to add any new operation but this is a hacky way for my environment only. Here we are trying to make an argument of a larger user need.

In addition, I am still wondering why not to have it in the baseline Redis to achieve an API parity with SETEX or SET and EX flag. An additional point from my use case is that our users of Dynomite cannot use transactions.

Comment From: HcgRandon

Yes, we are all very much aware of scripting and multi. My point is 'setex' current exists because "it is a common api use". Setex is atomic it is exactly equivalent to running set followed by expire. I'm proposing we add getex, because this is also a very common use case of redis. Setex exists without scripting or multi. I believe getex should as well

Comment From: mailsurfie

really expect this get and touch feature, and memcached also provides this convenient api.

Comment From: edwardboyle

Sometimes a voice gets lost in the mix. I have to add that I agree that this is a very common use scenario SETEX needs a corresponding GETEX, dare I say we have more uses for GETEX than we do for SETEX

Yes, using multi/exec will do, but I don't think it should have to be required for said common operation. It always feels like I am doing something wrong ...Like my SQL roots are getting in the way of my redis thinking.

Comment From: antirez

Hello, in theory, we may model something like this in a similar fashion as we did with SET, that is by passing arguments to GET. In practice this would turn GET as a write command depending on the parameters used, which is kinda of a problem... so basically if we want to model this pattern as a first class citizen, there is to add a GETEX command in an explicit way. I did not expect GETEX to be a very used pattern, even if I can see how it's pretty useful in certain conditions, please could you comment with your use cases in order to make a convincing argument about the generality of this combo command? Thanks.

Comment From: antirez

P.S. also note that we could potentially add this feature as an option for EXPIRE even if it's a very odd API in certain ways... So I would say it's not the case but just to bring all the options to the table.

Comment From: marcstreeter

I've not yet seen anyone comment here, so I hope I'm not spamming or posting in the wrong area. We're currently using it just to extend the time something is cached such that keys that are accessed often will stay longer and keys that are not accessed often will expire.

Comment From: firasd

"please could you comment with your use cases in order to make a convincing argument about the generality of this combo command?"

Sometimes various cached items have a wide distribution in terms of how often they're requested so it doesn't make sense to just have the same expiry time for all items of certain type.

I'm making an app that uses the Twitter API. I use Redis to cache the ID of tweets I've already added to MySQL. To save memory capacity, I don't want to persist all Redis items indefinitely.

I can set the same expiry time on every cached Tweet ID (e.g. three hours) and then---if it expires in Redis, but the popular tweet shows up retweeted on a user timeline that my app is reading---check my database again to confirm that the tweet has been added in MySQL, and cache the Tweet ID in Redis again for 3 hours.

But it would be better if the popular Tweet ID didn't expire from Redis, because every time I do a 'get' on it I extend the expiration time by another 3 hours.

Comment From: WhiteTrashLord

I think there are quite many use cases. Let's say you give all your keys an expiration time. With get and expire you make sure that only the keys which were recently used will be stored some more time. Keys which weren't accessed recently will be removed from the cache.

Comment From: itamarhaber

As someone who's surfin' the webz looking for mostly-Redis-related stuff, I can definitely say that an RW GETEX is more than a common requirement in the caching contexts brought above. It is, by far, the most intuitive way to kill these two birds with one simple op.

Comment From: petvas

please could you comment with your use cases in order to make a convincing argument about the generality of this combo command?

expensive data related to user session:
we have multiple app servers, and we use redis to share user data between servers, while the user is active in our site (navigating between pages) we need that data. When the user leaves the site (no more request) it is ok to get rid of this data from the redis server.

Comment From: fcamel

Is there any good news for this feature request? It'd be very helpful to implement an expire-after-access cache.

Comment From: itamarhaber

To summarize the discussion so far:

  • It looks like GET+EXPIRE is common enough <- let's resolve that already.
  • Modifying GET to support expiry semantics will make it into a write command, so that kind of a big change.
  • Modifying EXPIRE to also GET would be an awkward API, to say the least.

So, it looks like we need a new String 'write' command that is essentially GET amalgamated with SET's expiry verbiage, and possibly the AT variants as follows:

GETEX <key>  [KEEPTTL|[PERSIST|EX seconds|PX milliseconds|EXAT seconds-timestamp|PXAT milliseconds-timestamp]]`

Where KEEPTTL doesn't touch the TTL and is the default. PERSIST removes any TTL.

The reply would be an error, bulk-string, or nill.

Notes: * This can be used as a GETDEL (#6460, #7324) substitute of sorts when providing '0' to EX/PX or a past timestamp for EXAT/PXAT. Or if we make it accept a DEL option and think of EX as "extended" instead of "expire" :P * This could be another possible addition to 6.2 - @redis/core-team?

Comment From: oranagra

@itamarhaber another interesting idea that occurred to me that maybe SET XX NX GET EX <ttl> could do that (i.e. we allows both XX and NX to indicate that the key should not be modified). that's obviously a bad idea, but maybe we want to explore the possibility of extending the SET command with these features (DEL and NOSET) rather than the GETEX command you mentioned. it would still be more awkward than using a GETEX (but also a bit awkward that GETEX is a write command).

in any case, i do agree that it would be nice addition for 6.2 one way or another. (although there's really no disadvantage of doing that with MULTI-EXEC AFAIK)

Thinking about the above a bit more, i don't like the NOSET and DEL arguments since it means that the value argument is excessive. So i'm leaning towards GETEX and GETDEL (or GETEX with DEL argument, i.e. what they have in common is that they're a write command that returns the old value and don't take a new value argument). just wanted to put that idea above on the table.

p.s. if we add EXAT to GETEX, we should obviously add it to SET too.

Comment From: nmvk

Hi @itamarhaber @oranagra Has there been any decision if we would want this to be implemented as GETEX or as part of SET? For clarification, We are expecting GETEX to be like SETEX an independent command and would not be adding the arguments for GET as it would turn it into a write command?

Comment From: oranagra

@nmvk I think Itamar's last suggestion is the right one. I pinged the core team again. we can start looking for someone with a bit spare time to implement this.

Comment From: madolson

I find GETEX with a delete argument a little akward, but I couldn't think of anything better. GETEX with DEL sounds good enough for me.

I think @nmvk is looking to pick it up, since he's recently contributed.

Comment From: nmvk

Ack @madolson I will take a look at this.

Comment From: itamarhaber

ACK 👍

Comment From: HcgRandon

Amazing thank you guys <3