Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redis block until key exists

I'm new to Redis and was wondering if there is a way to be able to await geting a value by it's key until the key exists. Minimal code:

async def handler():
    data = await self._fetch(key)

async def _fetch(key):
    return self.redis_connection.get(key)

As you know, if such key doesnt exist, it return's None. But since in my project, seting key value pair to redis takes place in another application, I want the redis_connection get method to block untill key exists. Is such expectation even valid?

like image 487
Juggernaut Avatar asked Mar 04 '17 14:03

Juggernaut


People also ask

How to check if a key exists in Redis?

The Redis EXISTS command is used to check whether key exists in redis or not. Since Redis 3.0.3 it is possible to specify multiple keys instead of a single one. In such a case, it returns the total number of keys existing.

How to set the default value in Redis?

local value = redis.call ("GET", KEYS [1]) if (not value) then redis.call ("SET", KEYS [1], ARGV [1]) return ARGV [1] end return value You could also use SETNX to put the default value and then do a normal GET.

What is blpop in Redis and how does it work?

Redis has a few blocking commands among the built-in set of commands. One of the most used is BLPOP (or the symmetric BRPOP) which blocks waiting for elements arriving in a list. The interesting fact about blocking commands is that they do not block the whole server, but just the client calling them.

How do you check if a key exists in SQL?

EXISTS key [key ...] O (N) where N is the number of keys to check. Returns if key exists. The user should be aware that if the same existing key is mentioned in the arguments multiple times, it will be counted multiple times. So if somekey exists, EXISTS somekey somekey will return 2.


Video Answer


3 Answers

It is not possible to do what you are trying to do without implementing some sort of polling redis GET on your client. On that case your client would have to do something like:

async def _fetch(key):
    val = self.redis_connection.get(key)
    while val is None:
       # Sleep and retry here
       asyncio.sleep(1)  
       val = self.redis_connection.get(key)
    return val

However I would ask you to completelly reconsider the pattern you are using for this problem. It seems to me that what you need its to do something like Pub/Sub https://redis.io/topics/pubsub.

So the app that performs the SET becomes a publisher, and the app that does the GET and waits until the key is available becomes the subscriber.

I did a bit of research on this and it looks like you can do it with asyncio_redis:

  • Subscriber https://github.com/jonathanslenders/asyncio-redis/blob/b20d4050ca96338a129b30370cfaa22cc7ce3886/examples/pubsub/receiver.py.

  • Sender(Publisher): https://github.com/jonathanslenders/asyncio-redis/blob/b20d4050ca96338a129b30370cfaa22cc7ce3886/examples/pubsub/sender.py

Hope this helps.

like image 188
andrefsp Avatar answered Oct 17 '22 02:10

andrefsp


The closest you can get to this behavior is by enabling keyspace notifications and subscribing to the relevant channels (possibly by pattern).

Note, however, that notifications rely on PubSub that is not guaranteed to deliver messages (at-most-once semantics).

like image 29
Itamar Haber Avatar answered Oct 17 '22 02:10

Itamar Haber


Except the keyspace notification method mentioned by @Itamar Haber, another solution is the blocking operations on LIST.

  1. handler method calls BRPOP on an empty LIST: BRPOP notify-list timeout, and blocks until notify-list is NOT empty.
  2. The other application pushes the value to the LIST when it finishes setting the key-value pair as usual: SET key value; LPUSH notify-list value.
  3. handler awake from the blocking operation with the value you want, and the notify-list is destroyed by Redis automatically.

The advantage of this solution is that you don't need to modify your handler method too much (with the keyspace notification solution, you need to register a callback function). While the disadvantage is that you have to rely on the notification of another application (with keyspace notification solution, Redis does the notification automatically).

like image 4
for_stack Avatar answered Oct 17 '22 03:10

for_stack