Description
Symfony version(s) affected
6.X
Description
On my application the cache was not cleared when using the cache:clear
console command or clear()
method on the CacheItemPoolInterface
.
When inspecting the problem a bit deeper I noticed that Redis was only clearing the first 1000 keys. I was able to track down the problem to these lines https://github.com/symfony/symfony/blob/6.3/src/Symfony/Component/Cache/Traits/RedisTrait.php#L453-L467.
In my case $host
was an instance of Redis5Proxy (it seems to be injected automatically by Symfony) that returns the list of key when scan is called.
// $keys when scan() is called on a PredisClient
$keys = [
0 => '1234',
1 => [
'cache_key:1',
'cache_key:2',
'cache_key:3',
'cache_key:4',
]
];
// $keys when scan() is called on a Redix5Proxy
$keys = [
'cache_key:1',
'cache_key:2',
'cache_key:3',
'cache_key:4',
]
Since the keys are not what is expected by the system, the doClear()
method ends up cleaning only the first 1000 keys.
How to reproduce
To reproduce the problem you would need a redis runing, where you insert more than 1000 keys (I did it using the Cache)
In the cache.yaml
framework:
cache:
app: app.cache.adapter.redis
prefix_seed: mysite
default_redis_provider: '%env(resolve:REDIS_URL)%'
pools:
view_cache_pool:
default_lifetime: '7 days'
services:
app.cache.adapter.redis:
parent: 'cache.adapter.redis'
arguments:
$defaultLifetime: 604800
tags:
- { name: 'cache.pool', namespace: 'site_cache' }
Then a simple controller should work
<?php
namespace App\Http\Admin\Controller;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Routing\Annotation\Route;
class CacheController extends BaseController
{
#[Route(path: '/cache/clean', name: 'cache_clean', methods: ['GET'])]
public function clean(CacheItemPoolInterface $cache)
{
for ($i = 0; $i < 3000; $i++) {
$item = $cache->getItem("demo{$i}");
$item->set("demo{$i}");
$cache->save($item);
}
$cache->clear(); // Will only clear 1000 first items
}
}
Possible Solution
I see 2 possible solution at the moment :
- throw an error the host is Redis5Proxy or a class that doesn't work as expected
- Handle the case where we have no cursor. We could delete all the keys until keys array is empty ? But I don't know if there are possible side effects (risk of infinite loop)
Additional Context
No response