繁体   English   中英

正确使用 Node.js redis scanIterator

[英]Using Node.js redis scanIterator correctly

我试图一次从我的 redis 实例中检索 N 个密钥。 在这种情况下,我将 N 个键指定为batchSize = 100 此代码似乎无限循环,这表明我没有正确返回 cursor。 output无限循环: got a batch of 719 logs 我的测试数据库中共有 719 个键。 所以这在理论上应该循环retrieveLogs总共 8 次,有 7 批 100,还有一批 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();

主要问题是您在每次调用retrieveLogs()时收集所有结果,而main()中的while循环似乎准备好在每次调用时接受一大块项目。 事实并非如此,因为异步迭代器scanIterator()返回已经允许使用所有SCAN结果——隐藏了异步迭代器本身的复杂性。

因此,要解决此问题,您可以将while循环放在main()中,或者查看逻辑,以便调用scanIterator() main()迭代。

// ...

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()返回键而不是 cursor,因为实际的 cursor 隐藏在异步迭代器实现中。 因此,应该删除异步迭代中的短路逻辑,您可能还想相应地重命名该变量:

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的额外真实检查。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM