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

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

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

  1. /* eslint-disable no-await-in-loop */
  2. /* eslint-disable no-restricted-syntax */
  3. import { createClient } from 'redis';
  4. const redisClient = createClient({ url: process.env.REDIS_URL });
  5. redisClient.on('error', (err) => {
  6. console.log('Redis Client Error', err);
  7. throw new Error('Redis Client Error');
  8. });
  9. async function retrieveLogs(batchSize) {
  10. const logs = [];
  11. for await (const cursor of redisClient.scanIterator({
  12. MATCH: 'log:*',
  13. COUNT: batchSize,
  14. })) {
  15. const log = await redisClient.get(cursor);
  16. if (log) {
  17. logs.push(JSON.parse(log));
  18. }
  19. if (cursor === '0') {
  20. console.log('breaking');
  21. break;
  22. }
  23. }
  24. return logs;
  25. }
  26. async function main() {
  27. redisClient.on('error', (err) => {
  28. console.log('Redis Client Error', err);
  29. throw new Error('Redis Client Error');
  30. });
  31. await redisClient.connect();
  32. // Set the number of logs to retrieve and delete at a time
  33. const batchSize = 100;
  34. // Set a flag to indicate whether there are more logs to process
  35. let moreLogs = true;
  36. while (moreLogs) {
  37. // Retrieve a batch of logs from Redis
  38. // eslint-disable-next-line no-await-in-loop
  39. const batch = await retrieveLogs(batchSize);
  40. if (batch.length === 0) {
  41. // If there are no logs, set the flag to false to exit the loop
  42. moreLogs = false;
  43. break;
  44. }
  45. console.log(`got a batch of ${batch.length} logs`);
  46. }
  47. await redisClient.disconnect();
  48. }
  49. main();
jvlzgdj9

jvlzgdj91#

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

  1. // ...
  2. await redisClient.connect();
  3. // Retrieve a batch of logs from Redis
  4. const batch = await retrieveLogs(batchSize);
  5. console.log(`got a batch of ${batch.length} logs`);
  6. // TODO: Use the batch
  7. await redisClient.disconnect();
  8. // ...

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

  1. for await (const key of redisClient.scanIterator({
  2. MATCH: 'log:*',
  3. COUNT: batchSize,
  4. })) {
  5. const log = await redisClient.get(key);
  6. if (log) {
  7. logs.push(JSON.parse(log));
  8. }
  9. }

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

展开查看全部

相关问题