From 3c59e0fde8b63745e8f8b5a13845027035893848 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 7 Feb 2022 19:30:07 +0100 Subject: [PATCH] [Cache] fix error handling --- .../Component/Cache/Adapter/AbstractAdapter.php | 7 ++++++- .../Cache/Adapter/AbstractTagAwareAdapter.php | 15 ++++++++++++--- .../Cache/Adapter/RedisTagAwareAdapter.php | 12 ++++++++++-- src/Symfony/Component/Cache/Traits/RedisTrait.php | 3 ++- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 3b281bc87e8a8..59fe570b3123d 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -157,7 +157,12 @@ public function commit() $retry = $this->deferred = []; if ($expiredIds) { - $this->doDelete($expiredIds); + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } } foreach ($byLifetime as $lifetime => $values) { try { diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php index 16029f3608ce7..6b62ae9826481 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php @@ -181,7 +181,12 @@ public function commit(): bool if ($expiredIds) { // Tags are not cleaned up in this case, however that is done on invalidateTags(). - $this->doDelete($expiredIds); + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } } foreach ($byLifetime as $lifetime => $values) { try { @@ -295,8 +300,12 @@ public function invalidateTags(array $tags) $tagIds[] = $this->getId(self::TAGS_PREFIX.$tag); } - if ($this->doInvalidate($tagIds)) { - return true; + try { + if ($this->doInvalidate($tagIds)) { + return true; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to invalidate tags: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); } return false; diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php index b8b4b6f7b3134..3d950f9352756 100644 --- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php @@ -14,6 +14,7 @@ use Predis\Connection\Aggregate\ClusterInterface; use Predis\Connection\Aggregate\PredisCluster; use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Response\ErrorInterface; use Predis\Response\Status; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; @@ -58,6 +59,7 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter * @var string|null detected eviction policy used on Redis server */ private $redisEvictionPolicy; + private $namespace; /** * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis The redis client @@ -81,6 +83,7 @@ public function __construct($redis, string $namespace = '', int $defaultLifetime } $this->init($redis, $namespace, $defaultLifetime, new TagAwareMarshaller($marshaller)); + $this->namespace = $namespace; } /** @@ -160,7 +163,7 @@ protected function doDeleteYieldTags(array $ids): iterable }); foreach ($results as $id => $result) { - if ($result instanceof \RedisException) { + if ($result instanceof \RedisException || $result instanceof ErrorInterface) { CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]); continue; @@ -254,7 +257,7 @@ protected function doInvalidate(array $tagIds): bool $success = true; foreach ($results as $id => $values) { - if ($values instanceof \RedisException) { + if ($values instanceof \RedisException || $values instanceof ErrorInterface) { CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]); $success = false; @@ -303,6 +306,11 @@ private function getRedisEvictionPolicy(): string foreach ($hosts as $host) { $info = $host->info('Memory'); + + if ($info instanceof ErrorInterface) { + continue; + } + $info = $info['Memory'] ?? $info; return $this->redisEvictionPolicy = $info['maxmemory_policy']; diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index ce0a695ed4474..efff27296628d 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -14,6 +14,7 @@ use Predis\Connection\Aggregate\ClusterInterface; use Predis\Connection\Aggregate\RedisCluster; use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Response\ErrorInterface; use Predis\Response\Status; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; @@ -386,7 +387,7 @@ protected function doClear($namespace) } $info = $host->info('Server'); - $info = $info['Server'] ?? $info; + $info = !$info instanceof ErrorInterface ? $info['Server'] ?? $info : ['redis_version' => '2.0']; if (!$host instanceof \Predis\ClientInterface) { $prefix = \defined('Redis::SCAN_PREFIX') && (\Redis::SCAN_PREFIX & $host->getOption(\Redis::OPT_SCAN)) ? '' : $host->getOption(\Redis::OPT_PREFIX);