Symfony 3.1缓存 - DeleteItem在prod

时间:2016-10-16 13:13:01

标签: symfony caching redis symfony-3.1

我一直在使用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时,我会按照预期存储/删除数据。 但是当我将其更改为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格式,所以它不起作用,在开发模式下,它显示注意未定义的偏移0 错误

这是奇怪的部分

  • 在'dev'模式下,它会抛出一个错误,因此,deleteItems()将捕获它,并尝试再次删除该项,这次正确发送参数
  • 在'prod'模式下,注意未定义偏移量0 不知道原因,但它不会抛出异常,所以deleteItems(..)不会捕获它,返回就在那里..

我找到了一种方法让它适用于我,如果我在doDelete方法中添加array_values,它可以工作:

protected function doDelete(array $ids)
{
    if ($ids) {
        $this->redis->del(array_values($ids));
    }

    return true;
}

我不知道所有这些是否有意义,我想我会在symfony bug tracker中打开一个问题

1 个答案:

答案 0 :(得分:0)

我的不好,这是由一个过时的Predis版本造成的,我认为我有最新版本的Predis,但我没有

使用最新版本

一切正常
相关问题