ionelmc / python-redis-lock

Lock context manager implemented via redis SET NX EX and BLPOP.
https://pypi.python.org/pypi/python-redis-lock
BSD 2-Clause "Simplified" License
551 stars 77 forks source link

fix lua keys and args #75

Closed d9ichen closed 4 years ago

d9ichen commented 4 years ago

fix 'EVALSHA' command keys must in same slot error.

ionelmc commented 4 years ago

Can you give some details about the error?

d9ichen commented 4 years ago

Can you give some details about the error?

when this package is used with redis cluster. calling lock.release() will get ResponseError: 'EVALSHA' command keys must in same slot error.

code

import redis
import redis_lock

r = redis.StrictRedis(...)    # redis-cluster

lock = redis_lock.Lock(r, 'test-{lock}')    # use hash tag

lock.acquire()    # ok

lock.release()    # error

error

---------------------------------------------------------------------------
ResponseError                             Traceback (most recent call last)
<ipython-input-12-e3669b59a449> in <module>
----> 1 l.release()

/home/py37/lib/python3.7/site-packages/redis_lock/__init__.py in release(self)
    351             self._stop_lock_renewer()
    352         logger.debug("Releasing %r.", self._name)
--> 353         error = _eval_script(self._client, UNLOCK_SCRIPT, self._name, self._signal, self._signal_expire, args=(self._id,))
    354         if error == 1:
    355             raise NotAcquired("Lock %s is not acquired or it already expired." % self._name)

/home/py37/lib/python3.7/site-packages/redis_lock/__init__.py in _eval_script(redis, script_id, *keys, **kwargs)
    124         raise TypeError("Unexpected keyword arguments %s" % kwargs.keys())
    125     try:
--> 126         return redis.evalsha(SCRIPTS[script_id], len(keys), *keys + args)
    127     except NoScriptError:
    128         logger.info("%s not cached.", SCRIPTS[script_id + 2])

/home/py37/lib/python3.7/site-packages/redis/client.py in evalsha(self, sha, numkeys, *keys_and_args)
   3141         function exists purely for Redis API completion.
   3142         """
-> 3143         return self.execute_command('EVALSHA', sha, numkeys, *keys_and_args)
   3144
   3145     def script_exists(self, *args):

/home/py37/lib/python3.7/site-packages/redis/client.py in execute_command(self, *args, **options)
    899         try:
    900             conn.send_command(*args)
--> 901             return self.parse_response(conn, command_name, **options)
    902         except (ConnectionError, TimeoutError) as e:
    903             conn.disconnect()

/home/py37/lib/python3.7/site-packages/redis/client.py in parse_response(self, connection, command_name, **options)
    913         "Parses a response from the Redis server"
    914         try:
--> 915             response = connection.read_response()
    916         except ResponseError:
    917             if EMPTY_RESPONSE in options:

/home/py37/lib/python3.7/site-packages/redis/connection.py in read_response(self)
    754
    755         if isinstance(response, ResponseError):
--> 756             raise response
    757         return response
    758

ResponseError: 'EVALSHA' command keys must in same slot

info

System:
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.2 LTS
Release:    16.04
Codename:   xenial

Python Version: 3.7.7
Redis Client Version: 3.5.3
Redis Server Version: 2.8.19     2G(4 node)
        if self._lock_renewal_thread is not None:
            self._stop_lock_renewer()
        logger.debug("Releasing %r.", self._name)
        error = _eval_script(self._client, UNLOCK_SCRIPT, self._name, self._signal, self._signal_expire, args=(self._id,))

self._signal_expire should be a args not a key