Skip to content

Commit

Permalink
[Lock] Fix Predis error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed Feb 4, 2025
1 parent 4f6e8b0 commit e1dae80
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 12 deletions.
42 changes: 31 additions & 11 deletions Store/RedisStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Lock\Store;

use Predis\Response\Error;
use Predis\Response\ServerException;
use Relay\Relay;
use Symfony\Component\Lock\Exception\InvalidTtlException;
use Symfony\Component\Lock\Exception\LockConflictedException;
Expand Down Expand Up @@ -284,21 +285,18 @@ private function evaluate(string $script, string $resource, array $args): mixed

\assert($this->redis instanceof \Predis\ClientInterface);

$result = $this->redis->evalSha($scriptSha, 1, $resource, ...$args);
if ($result instanceof Error && str_starts_with($result->getMessage(), self::NO_SCRIPT_ERROR_MESSAGE_PREFIX)) {
$result = $this->redis->script('LOAD', $script);
if ($result instanceof Error) {
throw new LockStorageException($result->getMessage());
try {
return $this->handlePredisError(fn () => $this->redis->evalSha($scriptSha, 1, $resource, ...$args));
} catch (LockStorageException $e) {
// Fallthrough only if we need to load the script
if (!str_starts_with($e->getMessage(), self::NO_SCRIPT_ERROR_MESSAGE_PREFIX)) {
throw $e;
}

$result = $this->redis->evalSha($scriptSha, 1, $resource, ...$args);
}

if ($result instanceof Error) {
throw new LockStorageException($result->getMessage());
}
$this->handlePredisError(fn () => $this->redis->script('LOAD', $script));

return $result;
return $this->handlePredisError(fn () => $this->redis->evalSha($scriptSha, 1, $resource, ...$args));
}

private function getUniqueToken(Key $key): string
Expand Down Expand Up @@ -347,4 +345,26 @@ private function getNowCode(): string
now = math.floor(now * 1000)
';
}

/**
* @template T
*
* @param callable(): T $callback
*
* @return T
*/
private function handlePredisError(callable $callback): mixed
{
try {
$result = $callback();
} catch (ServerException $e) {
throw new LockStorageException($e->getMessage(), $e->getCode(), $e);
}

if ($result instanceof Error) {
throw new LockStorageException($result->getMessage());
}

return $result;
}
}
36 changes: 36 additions & 0 deletions Tests/Store/PredisStoreWithExceptionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Lock\Tests\Store;

/**
* @group integration
*/
class PredisStoreWithExceptionsTest extends AbstractRedisStoreTestCase
{
public static function setUpBeforeClass(): void
{
$redis = new \Predis\Client(array_combine(['host', 'port'], explode(':', getenv('REDIS_HOST')) + [1 => null]));
try {
$redis->connect();
} catch (\Exception $e) {
self::markTestSkipped($e->getMessage());
}
}

protected function getRedisConnection(): \Predis\Client
{
$redis = new \Predis\Client(array_combine(['host', 'port'], explode(':', getenv('REDIS_HOST')) + [1 => null]));
$redis->connect();

return $redis;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* @group integration
*/
class PredisStoreTest extends AbstractRedisStoreTestCase
class PredisStoreWithoutExceptionsTest extends AbstractRedisStoreTestCase
{
public static function setUpBeforeClass(): void
{
Expand Down

0 comments on commit e1dae80

Please sign in to comment.