Symfony 3.1 缓存 - DeleteItem 在产品中不起作用
Symfony 3.1 Cache - DeleteItem not working in prod
我一直在使用带有新缓存组件的 Symfony 3.1 (https://symfony.com/doc/current/components/cache.html),我正在使用 redis 适配器
config.yml
cache:
app: cache.adapter.redis
default_redis_provider: "redis://127.0.0.1:6379"
基本上,当我对特定资源执行 GET 时,我将数据保存在 redis 中,当我执行 POST..
时,我将其从 redis 中删除
在 symfony 的开发模式下,数据 stored/removed 如我所料来自缓存。
但是当我将它更改为 prod 时,'deleteItem' 不再从 redis 缓存中删除该项目。
我在日志中找不到任何错误,所以我有点迷路了..
这是我如何使用缓存的示例
protected function getCache(){
return $this->get('cache.app');
}
public function getAction(){
$cacheItem = $this->getCache()->getItem('example-key');
$data = ... // Check cacheItem isHit() ...
$cacheItem->expiresAfter($this->defaultCacheTime);
$cacheItem->set($data);
$this->getCache()->save($cacheItem);
}
public function postAction() {
...
$this->getCache()->deleteItem('example-key');
}
更新 - 我发现可能导致此问题的原因
这是 symfony AbstractAdapter 和 RedisAdapter 的部分代码:
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
public function deleteItems(array $keys)
{
$ids = array();
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
if ($this->doDelete($ids)) {
return true;
}
} catch (\Exception $e) {
}
$ok = true;
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete(array($id))) {
continue;
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
$ok = false;
}
return $ok;
}
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del($ids);
}
return true;
}
这是 Predis 的部分代码 StreamConnection.php:
public function writeRequest(CommandInterface $command)
{
$commandID = $command->getId();
$arguments = $command->getArguments();
$cmdlen = strlen($commandID);
$reqlen = count($arguments) + 1;
$buffer = "*{$reqlen}\r\n${$cmdlen}\r\n{$commandID}\r\n";
for ($i = 0, $reqlen--; $i < $reqlen; $i++) {
$argument = $arguments[$i];
$arglen = strlen($argument);
$buffer .= "${$arglen}\r\n{$argument}\r\n";
}
$this->write($buffer);
}
当我调用 deleteItem('example-key') 时,它会调用 deleteItems(..) 来删除那个键..
事实是,deleteItems() 正在调用 doDelete() 并传递一个数组,例如
'example-key' => 'prefix_example-key'
doDelete(),然后调用 Redis 客户端,传递相同的数组 string => string
,当我认为它应该是 index => string
,例如:[0] => 'prefix_example-key'
而不是 ['example-key'] => 'prefix_example-key'
然后 redis 客户端在处理要执行的命令时,接收该数组作为 $arguments,并在 for 循环中执行以下操作:
$argument = $arguments[$i];
因为数组是string => string
格式,它不会工作,在开发模式下,它显示 Notice undefined offset 0 error
这是奇怪的部分
- 在 'dev' 模式下,它会抛出错误,因此 deleteItems() 会捕获它,并尝试再次删除该项目,这次,正确发送参数
- 在'prod'模式下,Notice undefined offset 0不知道为什么,但是并没有抛出异常,所以deleteItems(..)不会'抓不住,returns 就在那里..
我找到了一种让它对我有用的方法,如果我在 doDelete 方法中添加 array_values,它就会起作用:
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del(array_values($ids));
}
return true;
}
我不知道所有这些是否有意义,我想我会在 symfony 错误跟踪器中打开一个问题
不好意思,这是Predis版本过时导致的,我以为我有最新版本的Predis,但我没有
最新版本一切正常
我一直在使用带有新缓存组件的 Symfony 3.1 (https://symfony.com/doc/current/components/cache.html),我正在使用 redis 适配器
config.yml
cache:
app: cache.adapter.redis
default_redis_provider: "redis://127.0.0.1:6379"
基本上,当我对特定资源执行 GET 时,我将数据保存在 redis 中,当我执行 POST..
时,我将其从 redis 中删除在 symfony 的开发模式下,数据 stored/removed 如我所料来自缓存。 但是当我将它更改为 prod 时,'deleteItem' 不再从 redis 缓存中删除该项目。 我在日志中找不到任何错误,所以我有点迷路了..
这是我如何使用缓存的示例
protected function getCache(){
return $this->get('cache.app');
}
public function getAction(){
$cacheItem = $this->getCache()->getItem('example-key');
$data = ... // Check cacheItem isHit() ...
$cacheItem->expiresAfter($this->defaultCacheTime);
$cacheItem->set($data);
$this->getCache()->save($cacheItem);
}
public function postAction() {
...
$this->getCache()->deleteItem('example-key');
}
更新 - 我发现可能导致此问题的原因
这是 symfony AbstractAdapter 和 RedisAdapter 的部分代码:
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
public function deleteItems(array $keys)
{
$ids = array();
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
if ($this->doDelete($ids)) {
return true;
}
} catch (\Exception $e) {
}
$ok = true;
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete(array($id))) {
continue;
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
$ok = false;
}
return $ok;
}
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del($ids);
}
return true;
}
这是 Predis 的部分代码 StreamConnection.php:
public function writeRequest(CommandInterface $command)
{
$commandID = $command->getId();
$arguments = $command->getArguments();
$cmdlen = strlen($commandID);
$reqlen = count($arguments) + 1;
$buffer = "*{$reqlen}\r\n${$cmdlen}\r\n{$commandID}\r\n";
for ($i = 0, $reqlen--; $i < $reqlen; $i++) {
$argument = $arguments[$i];
$arglen = strlen($argument);
$buffer .= "${$arglen}\r\n{$argument}\r\n";
}
$this->write($buffer);
}
当我调用 deleteItem('example-key') 时,它会调用 deleteItems(..) 来删除那个键..
事实是,deleteItems() 正在调用 doDelete() 并传递一个数组,例如
'example-key' => 'prefix_example-key'
doDelete(),然后调用 Redis 客户端,传递相同的数组 string => string
,当我认为它应该是 index => string
,例如:[0] => 'prefix_example-key'
而不是 ['example-key'] => 'prefix_example-key'
然后 redis 客户端在处理要执行的命令时,接收该数组作为 $arguments,并在 for 循环中执行以下操作:
$argument = $arguments[$i];
因为数组是string => string
格式,它不会工作,在开发模式下,它显示 Notice undefined offset 0 error
这是奇怪的部分
- 在 'dev' 模式下,它会抛出错误,因此 deleteItems() 会捕获它,并尝试再次删除该项目,这次,正确发送参数
- 在'prod'模式下,Notice undefined offset 0不知道为什么,但是并没有抛出异常,所以deleteItems(..)不会'抓不住,returns 就在那里..
我找到了一种让它对我有用的方法,如果我在 doDelete 方法中添加 array_values,它就会起作用:
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del(array_values($ids));
}
return true;
}
我不知道所有这些是否有意义,我想我会在 symfony 错误跟踪器中打开一个问题
不好意思,这是Predis版本过时导致的,我以为我有最新版本的Predis,但我没有
最新版本一切正常