php-lock / lock

Lock library to provide serialized execution of PHP code.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

Could be related to #14.

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.

Found the problem and was resolved in 845d29e.