私は 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 から削除します。
dev モードの 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」モードでは、Notice undefined offset 0は理由がわかりませんが、例外をスローしないため、deleteItems(..) はそれをキャッチせず、すぐに戻ります..
doDelete メソッドに array_values を追加すると、機能します。
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del(array_values($ids));
}
return true;
}
このすべてが理にかなっているのかどうかはわかりませんが、symfony バグトラッカーで問題を開くと思います