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

Fails when use StrictRedis with decode_responses=True #57

Closed tsionyx closed 5 years ago

tsionyx commented 7 years ago

When I creating a StrictRedis instance I always set the additional parameter decode_responses=True. However the lock is unusable with this setting because of manipulating with raw bytes self.id variable. As a result I get the following error:

    with redis_lock.Lock(name):
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis_lock/__init__.py", line 322, in __enter__
    acquired = self.acquire(blocking=True)
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis_lock/__init__.py", line 211, in acquire
    if self._held:
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis_lock/__init__.py", line 186, in _held
    return self.id == self.get_owner_id()
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis_lock/__init__.py", line 200, in get_owner_id
    return self._client.get(self._name)
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis/client.py", line 880, in get
    return self.execute_command('GET', name)
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis/client.py", line 573, in execute_command
    return self.parse_response(connection, command_name, **options)
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis/client.py", line 585, in parse_response
    response = connection.read_response()
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis/connection.py", line 577, in read_response
    response = self._parser.read_response()
  File "/home/tsionyx/.virtualenvs/test/lib/python3.5/site-packages/redis/connection.py", line 280, in read_response
    response = response.decode(self.encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9f in position 3: invalid start byte

Tested on Ubuntu 16.04 LTS, Python 2.7.12 and Python 3.5.2. Removing the decode_responses eliminates the problem.

ionelmc commented 7 years ago

I guess we could switch to asci ids? Base64 encoded perhaps. How about that?

tsionyx commented 7 years ago

I think it could help

alsbi commented 6 years ago

3.2 actual:

File "/usr/lib/python3/dist-packages/redis_lock/__init__.py", line 322, in __enter__
    acquired = self.acquire(blocking=True)
  File "/usr/lib/python3/dist-packages/redis_lock/__init__.py", line 211, in acquire
   if self._held:
   File "/usr/lib/python3/dist-packages/redis_lock/__init__.py", line 186, in _held
    return self.id == self.get_owner_id()
 File "/usr/lib/python3/dist-packages/redis_lock/__init__.py", line 200, in get_owner_id
   return self._client.get(self._name)
   File "/usr/lib/python3/dist-packages/redis/client.py", line 880, in get
    return self.execute_command('GET', name)
  File "/usr/lib/python3/dist-packages/redis/client.py", line 573, in execute_command
   return self.parse_response(connection, command_name, **options)
  File "/usr/lib/python3/dist-packages/redis/client.py", line 585, in parse_response
    response = connection.read_response()
   File "/usr/lib/python3/dist-packages/redis/connection.py", line 577, in read_response
   response = self._parser.read_response()
  File "/usr/lib/python3/dist-packages/redis/connection.py", line 280, in read_response
  response = response.decode(self.encoding)
 UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 1: invalid start byte
slumtrimpet commented 6 years ago

Not contributing anything to the conversation here aside to vote for a fix. 👍

Updated the Redis session for our locks to decode_response=False ... which was an easy enough fix for now, but it'd be nice if we didn't have to do that as we obviously can't reuse our Redis session objects anymore for other interfaces that rely on the decoding functionality.

Oh... also here's a 3.6 stack for what it's worth:

     File "./test.py", line 822, in test
       if lock.acquire(blocking=False):
     File "/x/test/env/live/lib/python3.6/site-packages/redis_lock/__init__.py", line 211, in acquire
       if self._held:
     File "/x/test/env/live/lib/python3.6/site-packages/redis_lock/__init__.py", line 186, in _held
       return self.id == self.get_owner_id()
     File "/x/test/env/live/lib/python3.6/site-packages/redis_lock/__init__.py", line 200, in get_owner_id
       return self._client.get(self._name)
     File "/x/test/env/live/lib/python3.6/site-packages/redis/client.py", line 976, in get
       return self.execute_command('GET', name)
     File "/x/test/env/live/lib/python3.6/site-packages/redis/client.py", line 668, in execute_command
       return self.parse_response(connection, command_name, **options)
     File "/x/test/env/live/lib/python3.6/site-packages/redis/client.py", line 680, in parse_response
       response = connection.read_response()
     File "/x/test/env/live/lib/python3.6/site-packages/redis/connection.py", line 624, in read_response
       response = self._parser.read_response()
     File "/x/test/env/live/lib/python3.6/site-packages/redis/connection.py", line 326, in read_response
       response = self.encoder.decode(response)
     File "/x/test/env/live/lib/python3.6/site-packages/redis/connection.py", line 125, in decode
       value = value.decode(self.encoding, self.encoding_errors)
   UnicodeDecodeError: 'utf-8' codec can't decode byte 0x97 in position 0: invalid start byte
foslock commented 5 years ago

+1, seems simple enough to use uuid.uuid4() instead of urandom(16) for ASCII IDs. You could always encode them if you wish them to remain as bytes objects.