| 1 |
<?php |
| 2 |
|
| 3 |
declare(strict_types=1); |
| 4 |
|
| 5 |
namespace malkusch\lock\mutex; |
| 6 |
|
| 7 |
use malkusch\lock\exception\LockAcquireException; |
| 8 |
use malkusch\lock\exception\LockReleaseException; |
| 9 |
use Predis\ClientInterface; |
| 10 |
use Predis\PredisException; |
| 11 |
|
| 12 |
/** |
| 13 |
* Mutex based on the Redlock algorithm using the Predis API. |
| 14 |
* |
| 15 |
* @author Markus Malkusch <[email protected]> |
| 16 |
* @license WTFPL |
| 17 |
* |
| 18 |
* @link http://redis.io/topics/distlock |
| 19 |
* @link bitcoin:1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA Donations |
| 20 |
*/ |
| 21 |
class PredisMutex extends RedisMutex |
| 22 |
{ |
| 23 |
/** |
| 24 |
* Sets the Redis connections. |
| 25 |
* |
| 26 |
* @param ClientInterface[] $clients The Redis clients. |
| 27 |
* @param string $name The lock name. |
| 28 |
* @param int $timeout The time in seconds a lock expires, default is 3. |
| 29 |
* |
| 30 |
* @throws \LengthException The timeout must be greater than 0. |
| 31 |
*/ |
| 32 |
public function __construct(array $clients, string $name, int $timeout = 3) |
| 33 |
{ |
| 34 |
parent::__construct($clients, $name, $timeout); |
| 35 |
} |
| 36 |
|
| 37 |
/** |
| 38 |
* @throws LockAcquireException |
| 39 |
*/ |
| 40 |
protected function add($redisAPI, string $key, string $value, int $expire): bool |
| 41 |
{ |
| 42 |
/** @var ClientInterface $redisAPI */ |
| 43 |
try { |
| 44 |
return $redisAPI->set($key, $value, 'EX', $expire, 'NX') !== null; |
| 45 |
} catch (PredisException $e) { |
| 46 |
$message = sprintf( |
| 47 |
"Failed to acquire lock for key '%s'", |
| 48 |
$key |
| 49 |
); |
| 50 |
throw new LockAcquireException($message, 0, $e); |
| 51 |
} |
| 52 |
} |
| 53 |
|
| 54 |
/** |
| 55 |
* @throws LockReleaseException |
| 56 |
*/ |
| 57 |
protected function evalScript($client, string $script, int $numkeys, array $arguments) |
| 58 |
{ |
| 59 |
/** @var ClientInterface $client */ |
| 60 |
try { |
| 61 |
return $client->eval($script, $numkeys, ...$arguments); |
| 62 |
} catch (PredisException $e) { |
| 63 |
throw new LockReleaseException('Failed to release lock', 0, $e); |
| 64 |
} |
| 65 |
} |
| 66 |
} |
| 67 |
|