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

Deadlock #27

Closed AndreiPashkin closed 9 years ago

AndreiPashkin commented 9 years ago

Here is current release Lua script:

if redis.call("get", KEYS[1]) == ARGV[1] then
    redis.call("del", KEYS[2])
    redis.call("lpush", KEYS[2], 1)
    return redis.call("del", KEYS[1])
else
    return 0
end

And here is acquire Python code:

while busy:
    busy = not self._client.set(self._name, self._id, nx=True, ex=self._expire)
    if busy:
        if timed_out:
            return False
        elif blocking:
            timed_out = not self._client.blpop(self._signal, blpop_timeout)
        else:
            logger.debug("Failed to get %r.", self._name)
            return False

Imagine such situation, with two workers:

In the result - worker-2 is blocked forever.

ionelmc commented 9 years ago

In Redis scripts are atomic. Everything is ran serially. Has this changed recently or are you using some redis-compatible implementation that is multi-threaded?

AndreiPashkin commented 9 years ago

Indeed, I just didn't knew about that.