PHPRedisMutex not working
cattivik66 opened this issue · comments
I have a simple piece of code:
$mutex = new \malkusch\lock\mutex\PHPRedisMutex([$app['redis']], "lock.".$guid, 8);
$mutex->synchronized(function () use ($object) {
echo 'test';
sleep(3);
});
but it throws the following exception:
LockReleaseException in SpinlockMutex.php line 94:
Failed to release the lock.
I am running PHP Version 7.0.15 with Redis extension 3.0.0
Seems that the problem is with the file PHPRedisMutex.php, at line 63:
return $redis->eval($script, $arguments, $numkeys);
At https://github.com/phpredis/phpredis#eval we can read:
Return value
Mixed. What is returned depends on what the LUA script itself returns, which could be a scalar value (int/string), or an array.
So, I have replaced the code at line 63 with:
$redis->eval($script, $arguments, $numkeys);
return $redis->getlasterror() == 0;
In that way it seems to work properly. I think that with the new php redis extension the return of the eval function has changed, and becouse of that it returns an unexpected value. So I have changed the code in a way that it returns a boolean, checking if redis encountered an error.
I'm not sure if that's the best way to fix that trouble, but with my tests it seems working.
After a more deep check, seems that the problem is not there, but related to the function release on file RedisMutex.php
$script = '
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
';
$released = 0;
foreach ($this->redisAPIs as $redis) {
try {
if ($this->evalScript($redis, $script, 1, [$key, $this->token])) {
$released++;
}
The problem is that the execution of $script returns always 0, becouse the value stored on Redis is a number, while the argument is a string. I am not good at LUA scripts, never used them, but if I change
if ($this->evalScript($redis, $script, 1, [$key, $this->token])) {
to
if ($this->evalScript($redis, $script, 1, [$key, 'i:'.$this->token.';'])) {
it seems working properly. I have found that checking the output of redis.call("GET",KEYS[1]) that was different from $this->token.
NOTE: I am using Redis 3.2.8
I've had a look, do you have OPT_SERIALIZER
enabled and set to something else than Redis::SERIALIZER_NONE
?
it seems working properly. I have found that checking the output of
redis.call("GET",KEYS[1])
that was different from$this->token
.
The call to SET will also be serialized, so it works fine for me. I've tested using ext-redis 4.0.0.