javascript 正确使用Node.js redis扫描迭代器

zbdgwd5y  于 2023-01-04  发布在  Java
关注(0)|答案(1)|浏览(117)

我试图从我的redis示例中一次检索N个键。在本例中,我将N个键指定为batchSize = 100。这段代码似乎无限循环,这表明我没有正确地将光标取回。输出无限循环:我的测试数据库中总共有719个键,所以理论上应该在retrieveLogs上循环8次,7批100个,1批19个。
我找不到关于如何正确使用它的文档,但这是我的整个程序。有什么地方我做错了吗?

/* eslint-disable no-await-in-loop */
/* eslint-disable no-restricted-syntax */
import { createClient } from 'redis';

const redisClient = createClient({ url: process.env.REDIS_URL });

redisClient.on('error', (err) => {
    console.log('Redis Client Error', err);
    throw new Error('Redis Client Error');
});

async function retrieveLogs(batchSize) {
    const logs = [];

    for await (const cursor of redisClient.scanIterator({
        MATCH: 'log:*',
        COUNT: batchSize,
    })) {
        const log = await redisClient.get(cursor);
        if (log) {
            logs.push(JSON.parse(log));
        }
        if (cursor === '0') {
            console.log('breaking');
            break;
        }
    }

    return logs;
}

async function main() {
    redisClient.on('error', (err) => {
        console.log('Redis Client Error', err);
        throw new Error('Redis Client Error');
    });

    await redisClient.connect();

    // Set the number of logs to retrieve and delete at a time
    const batchSize = 100;
    // Set a flag to indicate whether there are more logs to process
    let moreLogs = true;

    while (moreLogs) {
        // Retrieve a batch of logs from Redis
        // eslint-disable-next-line no-await-in-loop
        const batch = await retrieveLogs(batchSize);

        if (batch.length === 0) {
            // If there are no logs, set the flag to false to exit the loop
            moreLogs = false;
            break;
        }
        console.log(`got a batch of ${batch.length} logs`);
    }

    await redisClient.disconnect();
}

main();
jvlzgdj9

jvlzgdj91#

主要的问题是,您收集了所有retrieveLogs()的**调用的结果,而main()中的while循环似乎准备在每次调用时接受一个项目块。因为异步迭代器scanIterator()返回已经允许消耗所有SCAN结果-隐藏了异步迭代器本身的复杂性。
因此,要解决这个问题,您可以删除main()中的while循环,或者查看逻辑,以便在main()中迭代对scanIterator()的调用结果。

// ...

await redisClient.connect();

// Retrieve a batch of logs from Redis

const batch = await retrieveLogs(batchSize);
console.log(`got a batch of ${batch.length} logs`);

// TODO: Use the batch

await redisClient.disconnect();

// ...

另外,scanIterator()返回键而不是游标,因为实际的游标隐藏在异步迭代器实现中,所以异步迭代中的短路逻辑应该被删除,您可能还需要相应地重命名该变量:

for await (const key of redisClient.scanIterator({
    MATCH: 'log:*',
    COUNT: batchSize,
})) {
    const log = await redisClient.get(key);
    if (log) {
        logs.push(JSON.parse(log));
    }
}

而且...... scanIterator()返回的键肯定存在,因此您 * 甚至可以 *(取决于您的解析逻辑)删除对log的额外真实性检查。

相关问题