Redis keys are not expiring - Laravel, Predis
Asked Answered
O

5

16

I am using Laravel 5.4, with Predis and the latest Redis (or Redis for Windows).

The keys are being saved without issue. So, I doubt it's a configuration issue.

The problem is that they are not expiring. The key is reused until it expires...similar to how a session works.

I create the key once, if it does not exist. In that same logic I then set the expiration time.

In the Controller, I have

use Illuminate\Support\Facades\Redis;

In one of the functions, Get the connection instance:

$redis = Redis::connection();

Before I create the key, I check the existence (simplified) then create and set expiration.

if(!$redis->exists($some_unique_key))
{
   //set the key
   $redis->set($some_unique_key, 'Some Value'));
   //set the expiration
   //I understand this means expire in 60s.
   $redis->expire($some_unique_key,60); 
}

Why could it not be expiring the key?

As I mentioned, everything else works. I see the key updating without issue if I monitor, and can query it.

For the record, I have read:

There is nothing on expiration on the Laravel documentation:

UPDATE 1

Investigating a possible cause where setting(updating) the key resets the expiry

UPDATE 2

Used @for_thestack's reasoning (in REDIS commands) to come up with the solution. See my answer with the code. Feel free to upvote @for_thestack :)

Oxidase answered 21/4, 2017 at 18:29 Comment(2)
it doesn't really make sense, if you request a key and the expiration time has passed, it will be immediately deleted. Are you sure there is no statement that set the expire time for the key before the 60seconds pass ? try TTL for the key to check itPallaten
Thanks for the comments @Mr.Phoenix. I did end up using TTL in the process of getting to my answerOxidase
B
7

Some other process might call SET to update the key-value pair, in this case, the expiration will be removed.

// set expiration
EXPIRE key expiration_in_seconds
// update key-value pair with no expiration
SET key new_value
// now, expiration has been reset, and the key won't be expired any more

In order to keep the expiration, when you update the key-value pair, you should call SET with expiration parameters.

// get TTL, i.e. how much time left before the key will be expired
TTL key
// update with expiration parameter
SET key new_value EX ttl

You can wrap the two commands into a lua script to make it atomic. And you also need to take care of the case that key doesn't exist when you call TTL. See the document for details.

Brummell answered 22/4, 2017 at 1:2 Comment(5)
Makes alot of sense. I get where TTL fits in now. I will use that as pseudo code for my case, if it works...which I think it will...yours is the answer!Oxidase
Thanks @Brummell , that did it. Will credit you for the answer and will post the actual solution for my caseOxidase
How do you translate this in laravel though, documentation doesn't specify the set. laravel.com/docs/5.7/redisStarkey
@MarkOdey Sorry, I'm not familiar with Laravel. Please check if user919426's answer can help you.Brummell
@Brummell Finally the laravel docs provides the answer. It would look something like this Redis::set(''mykey", "1", 'EX', "3600"). Basically the idea is that arguments are just mapped from redis spec to php.Starkey
S
47

For those who uses Laravel, it is possible to use EX param (expire resolution) + ttl. In below example EX means that TTL is expressed in seconds (see Redis docs: https://redis.io/commands/set). So the result of below will be that $val stored under $key will be removed after 35 seconds.

Redis::set($key, $val, 'EX', 35);

In predis u can use the same, actually Laravel uses predis under the hood.

Sirkin answered 21/4, 2018 at 12:44 Comment(1)
This doesn't answer the question. The issue was to do with the misunderstood workflow of how to handle keys and expire them. It should be a comment or suggestion on the selected answer or my answer.Oxidase
B
7

Some other process might call SET to update the key-value pair, in this case, the expiration will be removed.

// set expiration
EXPIRE key expiration_in_seconds
// update key-value pair with no expiration
SET key new_value
// now, expiration has been reset, and the key won't be expired any more

In order to keep the expiration, when you update the key-value pair, you should call SET with expiration parameters.

// get TTL, i.e. how much time left before the key will be expired
TTL key
// update with expiration parameter
SET key new_value EX ttl

You can wrap the two commands into a lua script to make it atomic. And you also need to take care of the case that key doesn't exist when you call TTL. See the document for details.

Brummell answered 22/4, 2017 at 1:2 Comment(5)
Makes alot of sense. I get where TTL fits in now. I will use that as pseudo code for my case, if it works...which I think it will...yours is the answer!Oxidase
Thanks @Brummell , that did it. Will credit you for the answer and will post the actual solution for my caseOxidase
How do you translate this in laravel though, documentation doesn't specify the set. laravel.com/docs/5.7/redisStarkey
@MarkOdey Sorry, I'm not familiar with Laravel. Please check if user919426's answer can help you.Brummell
@Brummell Finally the laravel docs provides the answer. It would look something like this Redis::set(''mykey", "1", 'EX', "3600"). Basically the idea is that arguments are just mapped from redis spec to php.Starkey
D
7

If you're using Laravel and the Redis Fassade, you can also do

Redis::setex('yourkey', 120, 'your content'); // 120 seconds

instead of

Redis::set('yourkey', 'your content', 'EX', 120);

I'm not sure if it was already possible in Laravel 5.4. But definitely with Laravel 8 and Predis 1.1.

Drawknife answered 9/7, 2021 at 14:10 Comment(0)
O
6

Since @for_stack provided me with the logic(in REDIS commands & logic), I accepted his contribution as the answer.

My problem was that I did not know that seting the key, resets the expiry. So making it work, as explained by @for_stack involves:

  1. getting the TTL if the key exists
  2. after updating the key, set the expiration to the TTL that I got from (1)

It means that the overall TTL is not precise. There is a margin of milli or micro seconds that it takes between the time I got the TTL value in (1) to the time I update it.... which is fine by me!

So for my Laravel(PHP), Predis scenario, I do the following:

At some relevant point, higher up in the code:

//get ttl - time left before expiry
$ttl = $redis->ttl($some_unique_key);

Then wherever I have to update the value, I set the expiry after setting the value. The logic for creating the key(in my question) remains correct and unchanged.

//***note that I am UPDATING a key. Checking if it exists then I update
if($redis->exists($some_unique_key))
{
   //set/up the key
   $redis->set($some_unique_key, 'Some New, Updated, Value'));

   //Do some work   

   //set the expiration with the TTL value from (1)
   $redis->expire($some_unique_key,$ttl); 
}

Works perfectly!

Oxidase answered 22/4, 2017 at 9:24 Comment(0)
P
0

This method worked for me

use Illuminate\Support\Facades\Redis;


Redis::rpush("REDIS_KEY", ['start' => microtime(true)]);

//get all redis data
$redisData = Redis::lrange("REDIS_KEY", 0, -1);
dd($redisData);
Peria answered 14/7, 2023 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.