phpredispredis

Infinite loop when using predis SCAN


I'm trying to replace the keys function from predis for scan in order to increase the performance in some parsing that we do.

The problem is that when I do the scan operation it seems to fall into an infinite loop, which makes no sense because according to the redis documentation scan will return the iterator to 0 when it's done.

        $it = null;
        $keysFound = [];

        do {

            $redisKeys = $redis->scan($it,"*{$query}", 10);

            if (!empty($keys)) {
                array_merge($keysFound, $redisKeys);
            }
        } while($it != 0);

I just want to replace it so we don't do this

$keys = $redis->keys("*{$query}");

I have tried everything, please some help.

UPDATE Checking on the cli I see that it never finds the key and stays in loop even if I put the exact same key that I can see in redsmin.

127.0.0.1:6379> scan 122880 MATCH x_dashboard_dashboard_row_1005_251 
1) "118784"
2) (empty list or set)
127.0.0.1:6379> scan 118784 MATCH x_dashboard_dashboard_row_1005_251 
1) "18432"
2) (empty list or set)
127.0.0.1:6379> scan 18432 MATCH x_dashboard_dashboard_row_1005_251 
1) "59392"
2) (empty list or set)
127.0.0.1:6379> scan 59392 MATCH x_dashboard_dashboard_row_1005_251 
1) "63488"
2) (empty list or set)
127.0.0.1:6379> scan 63488 MATCH x_dashboard_dashboard_row_1005_251 
1) "123904"
2) (empty list or set)
127.0.0.1:6379> scan 123904 MATCH x_dashboard_dashboard_row_1005_251 
1) "19456"
2) (empty list or set)
127.0.0.1:6379> scan 19456 MATCH x_dashboard_dashboard_row_1005_251 
1) "121856"
2) (empty list or set)
127.0.0.1:6379> scan 121856 MATCH x_dashboard_dashboard_row_1005_251 
1) "115200"
2) (empty list or set)
127.0.0.1:6379> scan 115200 MATCH x_dashboard_dashboard_row_1005_251 
1) "119296"
2) (empty list or set)
127.0.0.1:6379> scan 119296 MATCH x_dashboard_dashboard_row_1005_251 
1) "109056"
2) (empty list or set)
127.0.0.1:6379> 

Is there something that could be wrongly configured? I have never worked with redis before so I don't know if it could be wrong configuration related.

SOLVED The issue was that we have a very big amount of keys so increasing the COUNT value to a bigger amount gave the correct results.


Solution

  • If you want to do the scan yourself, then you need to capture the returned cursor from the response:

    $it = null;
    $keysFound = [];
    
    do {
    
        $response = $redis->scan($it,"*{$query}", 10);
    
        $it = $response[0];
        $redisKeys = $response[1];
    
        if (!empty($keys)) {
            array_merge($keysFound, $redisKeys);
        }
    } while($it != 0);
    

    See https://redis.io/commands/scan to understand the response.

    But take a look at the iterators, as you may be reinventing the wheel (taken from How to use SCAN with the MATCH option in Predis, added count):

    use Predis\Collection\Iterator;
    
    $client = ...;
    $pattern = 'foo*';
    $count = 100;
    
    foreach (new Iterator\Keyspace($client, $pattern, $count) as $key) {
        ...
    }