Skip to content

Commit 174837a

Browse files
committed
Use Lua script in Redis to flush cache tags atomically, ensuring consistency and preventing partial updates during flushing operations
1 parent 294661d commit 174837a

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

src/Illuminate/Cache/RedisTaggedCache.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,44 @@ public function forever($key, $value)
9393
*/
9494
public function flush()
9595
{
96-
$this->flushValues();
97-
$this->tags->flush();
96+
/** @var \Illuminate\Cache\RedisStore $redis_store */
97+
$redis_store = $this->store;
98+
99+
$redis_connection = $redis_store->connection();
100+
$redis_prefix = match ($redis_connection::class) {
101+
\Illuminate\Redis\Connections\PhpRedisConnection::class => $redis_connection->client()->getOption(\Redis::OPT_PREFIX),
102+
\Illuminate\Redis\Connections\PredisConnection::class => $redis_connection->client()->getOptions()->prefix,
103+
};
104+
105+
/** @var \Illuminate\Cache\RedisTagSet $redis_tag_set */
106+
$redis_tag_set = $this->tags;
107+
$entries = $redis_tag_set->entries();
108+
109+
$cache_tags = [];
110+
$need_deleted_keys = [];
111+
112+
$cache_prefix = $redis_prefix.$redis_store->getPrefix();
113+
114+
foreach ($this->tags->getNames() as $name) {
115+
$cache_tags[] = $cache_prefix.$this->tags->tagId($name);
116+
}
117+
118+
foreach ($entries as $entry) {
119+
$need_deleted_keys[] = $redis_store->getPrefix().$entry;
120+
}
121+
122+
$lua_script = <<<'LUA'
123+
local prefix = table.remove(ARGV, 1)
124+
for i, key in ipairs(KEYS) do
125+
redis.call('DEL', key)
126+
for j, arg in ipairs(ARGV) do
127+
local zkey = string.gsub(key, prefix, "")
128+
redis.call('ZREM', arg, zkey)
129+
end
130+
end
131+
LUA;
132+
133+
$redis_connection->eval($lua_script, count($need_deleted_keys), ...$need_deleted_keys, ...[$cache_prefix, ...$cache_tags]);
98134

99135
return true;
100136
}

0 commit comments

Comments
 (0)