Redis setting TTL on hSet Keys - caching

I am on an dead end with redis cache. I want to set an TTL on the initiation of a key. The key will be set by hSet($hash, $key, $data)
expire($key, '3600')
does not seem to work. Is there an hExpire() method?

Explanation:
Redis supports expiration only on KEY level. It does not support expiration on inner element(s) of any data structure, let alone hash.
Answer:
No. There is no hExpire method/command in Redis.
You're trying expire an inner element in a hash. This is not possible in Redis.
Update:
You can expire a whole data structure (a.k.a. a key).
One of the command to expire key is EXPIRE key seconds.
Assuming you are using phpredis, your method call can be setTimeout($hash, 3600).

You need to put the TTL on the $hash itself as you can't expire individual keys of a hash.

You can try TairHash, which is a redis module, similar to redis hash, but you can set expire and version for the field: https://github.com/alibaba/TairHash

Related

Check keys' expire times through the redis-cli

I have a question about Redis caching.
I wrote some code to cache some information and it works fine, but is there a way to check what's being stored inside of it through redis-cli? I just want to make sure that the value gets deleted after 10 minutes.
how I store stuff:
Cache::store('redis')->put('inventory_' . $this->user->steamid64, $items, 15);
Since you are using laravel's Cache class instead of Redis - then you need to check for the prefix. By default it ships like this in config/cache.php
'prefix' => env('CACHE_PREFIX', 'laravel')
If there is a prefix(and it is laravel) it is going to be like this (if there is no prefix then you may discard laravel: from the key names)
127.0.0.1:6379> get laravel:inventory_1
"somevalue"
127.0.0.1:6379> ttl laravel:inventory_1
(integer) 885
127.0.0.1:6379>
For the "development" purpose you may also use monitor command to see which commands are executed in redis. It is going to print like this;
127.0.0.1:6379> monitor
OK
1591091085.487083 [0 127.0.0.1:51828] "set" "myinventory_1" "myvalue" "EX" "900"
1591091091.143395 [0 127.0.0.1:51828] "get" "myinventory_1"
1591091095.280724 [0 127.0.0.1:51828] "ttl" "myinventory_1"
Side note: You don't need to call store method if your default cache driver is already redis.
Enter the redis-cli and use:
keys * to see list of all keys
TTL my_key_name to see remaining expire time of the key
You can execute any of Redis commands inside of the redis-cli. It's good tool for development.

using Redis in Openstack Keystone, some Rubbish in redis

Recently, I'm using Redis to cache token for OpenStack Keystone. The function is fine, but some expired cache data still in Redis.
my Keystone config:
[cache]
enabled=true
backend=dogpile.cache.redis
backend_argument=url:redis://127.0.0.1:6379
[token]
provider = uuid
caching=true
cache_time= 3600
driver = kvs
expiration = 3600
but some expired data in Redis:
Data was over expiration time, but still in here, because the TTL is -1.
My question:
How can I change settings to stop this rubbish data created?
Is some gracefully way to clean it up?
I was trying to use command 'keystone-manage token_flush', but after reading code, I realized this command just clean up the expired tokens in Mysql
I hope this question still relevant.
I'm trying to do the same thing as you are, and for now the only option I found working is the argument on dogpile.cache.redis: redis_expiration_time.
Checkout the backend dogpile.redis API or source code.
http://dogpilecache.readthedocs.io/en/latest/api.html#dogpile.cache.backends.redis.RedisBackend.params.redis_expiration_time
The only problem with this argument is that it does not let you choose a different TTL for different categories, for example you want tokens for 10 minutes and catalog for 24 hours or so. The other parameters on keystone.conf just don't work from my experience (expiration_time and cache_time on each category)... Anyway this problem isn't relevant if you are using redis to store only keystone tokens.
[cache]
enabled=true
backend=dogpile.cache.redis
backend_argument=url:redis://127.0.0.1:6379
// Add this line
backend_argument=redis_expiration_time:[TTL]
Just replace the [TTL] with your wanted ttl and you'll start noticing keys with ttl in redis and after a while you will see that they are no more.
about the second question:
This is maybe not the best answer you'll see, but you can use OBJECT idletime [key] command on redis-cli to see how much time the specific key wasn't used (even GET reset idletime). You can delete the keys that have bigger idletime than your token revocation using a simple script.
Remember that the data on Redis isn't persistent data, meaning you can always use FLUSHALL and your OpenStack and keystone will work as usual, but ofc the first authentications will take longer.

Redis subscriber is not notified by EXPIRE key 0

I've got a Redis client subscribed to __keyevent#0__:expired notifications. It works perfectly, either when the key expires by itself (ttl reached) or when I expire them manually with a number of seconds greater than 0, like so:
EXPIRE myKey 1
The subscriber sees the expired event and can therefore take some actions.
However, if I want to manually delete the key and have the subscriber notified, I use EXPIRE with 0 as the number of seconds:
EXPIRE myKey 0
The key gets deleted, but the subscriber doesn't receive anything.
I can't see anything related to this in the doc. Can anyone explain this behavior?
From reviewing the source code (expire.c, ~252), setting an expiry value of <=0 (or using EXPIREAT with a time in the past) results in a deletion of the key rather than an expiry (and accordingly a DEL notification rather than an EXPIRED event).
This behavior is indeed undocumented and it would be good if you could submit a PR that fixes that to the documentation repo (https://github.com/antirez/redis-doc).

Dealing with Memcached Race Conditions

I have two different sources of data which I need to marry together. Data set A will have a foo_key attribute which can map to Data set B's bar_key attribute with a one to many relationship.
Data set A:
[{ foo_key: 12345, other: 'blahblah' }, ...]
Data set B:
[{ bar_key: 12345, other: '' }, { bar_key: 12345, other: '' }, { bar_key: 12345, other: '' }, ...]
Data set A is coming from a SQS queue and any relationships with data set B will be available as I poll A.
Data set B is coming from a separate SQS queue that I am trying to dump into a memcached cache to do quick look ups on when an object drops into data set A.
Originally I was planning on setting the memcached key to be bar_key from the objects in data set B but then realized that if I did that it would be possible to overwrite the value since there can be many of the same bar_key value. Then I was thinking well I can create a key bar_key and the value just be an array of the SQS messages. But since I have multiple hosts polling the SQS queue I think it might be possible that when I check to see if the key is in memcached, check it out, append the new message to it, and then set it, that another host could be trying to preform the same operation and thus the first host's attempt at appending the value would just be overwritten.
I've looked around at memcached key locking but I'm not sure I understand it entirely. Would the solution be that when I get the key/value pair from memcached I create a temporary dummy lock on a new key called bar_key_dummy that expires in x seconds, and if I try to fetch a key that has a bar_key_dummy lock active I just send the SQS message back to the queue without deleting to try again in x seconds?
Here's some pseudocode for what I have going on in my head. Does this make any sense?
store = MemCache.new(host)
sqs_messages.poll do |message|
dummy_key = "#{message.bar_key}_dummy"
sqs.dont_delete_message && next unless store.get(dummy_key).nil?
# set dummy_key in memcache with a value of 1 for 3 seconds
store.set(dummy_key, 1, 3)
temp_data = store.get(message.bar_key) || []
temp_data << message
store.set(message.bar_key, temp_data, 300)
# delete dummy key when done in case shorter than x seconds
store.delete(dummy_key)
end
Thanks for any help!
Memcached has a special operation - cas Compare and Swap.
Command gets returns Item along with its unique CAS value.
Then dataset can be searched and update must be issued with the cas command which takes original unique CAS value.
If CAS was changed in between two command, update operation will fail with the EXISTS error

How to automatically delete a memcache after some time in Dalli

I'm not sure if this can be done at all.
I'm trying to set Dalli to delete a memcache after 3 seconds (just to experiment)
dalli = Dalli::Client.new
dalli.add("test1","value", 3)
dalli.get("test1").should eql "value"
sleep(10)
dalli.get("test1").should eql nil
In the code, I have set TTL for 3 seconds, and then I expect that after 3 seconds the "test1" would be deleted but apparently not. So, the test fails in the second assertion. How can I ask Dalli to expire a key/value after a certain amount of time?
Thanks a lot.
You can only explicitly remove a key by calling delete or implicitly via TTL.
Does this happen with a different key besides 'test1'? Try changing your 'add' command to a 'set' command. The add command is conditional, it only sets the value if doesn't already exist. Is it possible you already set that key previously (although unlikely from the code you provided) without specifying a TTL? If you didn't specify a TTL the item is cached indefinitely.
Put the following in your session_store.rb initializer
Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes
That will expire the cache after 20 minutes.

Resources