Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Lock with redis-py

I'm trying to create a lock on a redis value in a django project, but am having trouble. Non blocking code works just fine, ie:

r = redis.StrictRedis(host='localhost', port=6379)
data_dict = {'key': 'value'}
r.hmset('hash', data_dict)

However when trying to use a lock to prevent other threads from writing to this, with code:

r = redis.StrictRedis(host='localhost', port=6379)
data_dict = {'key': 'value'}
lock = r.lock('hash')
with lock.acquire() as l:
    r.hmset('hash', data_dict)

throws:redis.exceptions.ResponseError: WRONGTYPE Operation against a key holding the wrong kind of value

I apologize if this is a very stupid question but I don't understand how I'm getting that error, the data being set is literally the same

like image 360
Kevin Qualters Avatar asked Dec 09 '15 05:12

Kevin Qualters


People also ask

How do I lock a Redis in Python?

from redis import Redis conn = Redis() import redis_lock lock = redis_lock. Lock(conn, "name-of-the-lock") if lock. acquire(blocking=False): print("Got the lock.") lock. release() else: print("Someone else has the lock.")

Can Redis be used for locking?

The simplest way to use Redis to lock a resource is to create a key in an instance. The key is usually created with a limited time to live, using the Redis expires feature, so that eventually it will get released (property 2 in our list). When the client needs to release the resource, it deletes the key.

Can I use Redis with Python?

To connect and use Redis with Python, we need a Python-Redis client. For this process, we will opt for redis-py as it is easy to use and configure. The previous command should download and install the Redis-py client.


2 Answers

There are two problems:

  1. As others have said, you need to use two different keys for the lock and the hash.
  2. The syntax is wrong.

To elaborate on point 2, here are the steps involved with using a lock:

  1. Create a Lock object.
  2. Acquire the lock.
  3. Do critical stuff.
  4. Release the lock.

Without using a context manager (the with ... statement), the code might look like this:

lock = r.lock('my_lock')
lock.acquire(blocking=True)
r.set('foo', 'bar')
lock.release()

With a context manager, that code gets simplified to this:

with r.lock('my_lock'):
    r.set('foo', 'bar')

What is happening here is the following:

  1. r.lock() creates and returns a Lock object.
  2. Lock.__enter__() is called automatically, which in turn calls Lock.acquire().
  3. The indented code executes.
  4. Lock.__exit__() is called automatically, which in turn calls Lock.release().

You can see this in the redis-py source code.

  • client.py (contains lock())
  • lock.py (contains the Lock class)
like image 163
MarredCheese Avatar answered Sep 23 '22 23:09

MarredCheese


You are trying to set a dictionary in the same key as the lock. You want to have a key for the lock and another for the dictionary.

like image 30
Pablo Gonzalez Portela Avatar answered Sep 26 '22 23:09

Pablo Gonzalez Portela