Redis: SCAN is not SCAN
In a Laravel application, it's crucial to always be aware of which Redis client you’re using. Different Redis clients (such as predis or phpredis) can have varying levels of performance, feature support, and configuration differences. Especially when it comes to the implementation of the SCAN command, there are differences that may not be immediately apparent.
A few days ago, we encountered a requirement to search for similarities among keys within a massive pool of keys. So far, no problem.
1$keys = Redis::keys($pattern);2 3foreach ($keys as $key) {4 Log::info($key);5}
Normally, this code would fulfill the requirement. The problem, however, is that the application for which we implemented this functionality handles several million requests per day, resulting in a massive set of caching keys in Redis.
The solution is SCAN. Unlike KEYS, which retrieves all keys at once, SCAN iterates over the data, requiring a cursor to manage the results. But so far, this isn’t the issue.
Our next iteration was a classic attempt at iteration in Redis:
1$pattern = '/test/*' 2$cursor = '0'; 3$count = 50000; 4do { 5 $result = $redis->scan($cursor, ['match' => $pattern, 'count' => $count]); 6 if ($result === false) { 7 break; 8 } 9 10 $cursor = $result[0];11 $allResults = array_merge($allResults, $result[1]);12 13} while ($cursor !== '0');
An experienced eye will quickly notice that this implementation is primarily designed for PREDIS, a Redis client written in PHP.
Honestly, this caught us off guard. While our developers had been using Predis (perhaps out of convenience for setup 😉), the PHPRedis client, which is written in C, was set up in our staging environment.
The problem with this code is: It will not work with PHPRedis or at least it will not return any result. To change this you need to adjust the code a bit.
1$pattern = '/test/*' 2$cursor = config('database.redis.client') == 'predis' ? '0' : null; 3$count = 50000; 4do { 5 $result = $redis->scan($cursor, ['match' => $pattern, 'count' => $count]); 6 if ($result === false) { 7 break; 8 } 9 10 $cursor = $result[0];11 $allResults = array_merge($allResults, $result[1]);12 13} while ($cursor !== '0');
The result of this difference was absolutely absurd. Due to the slight variations in cursor handling between the clients, we ended up with no results at all.
So, always keep an eye on which Redis client you're using in Laravel! 🚀
Feel like cooking this up together?
Whether it's an idea, a refactor, or a new build — tell us briefly about your project. We'll get back to you within 24 hours.
Weiterlesen
15. Jun 2026
Building Responsive Images: The Complete srcset & sizes Guide
Responsive images without hand-waving: how srcset and sizes really work, picture for art direction — and how to generate the variants instead of maintaining them by hand.
06. Jun 2026
Core Web Vitals Are an Image Problem – And How Fairu Solves It
LCP is the Core Web Vital most sites fail — and images are almost always to blame. How Fairu gets them passing, with no pipeline of your own.
10. May 2026
Release 1.109 - Now supports google + github login
Starting today, you can sign in to Fairu with Google or GitHub — no separate password needed anymore.