使用ioredis编写简单的Node redis循环的更好方法是什么?

4

所以,我一直在从其他语言学习JS/Node的方式。

我有一个小型微服务,它从redis通道读取,将其暂时存储在工作通道中,进行处理,然后删除并继续。如果通道中还有更多内容,则立即重新运行。如果没有,则设置超时并在1秒后再次检查。

它可以正常工作...但是超时轮询似乎不是"正确"的方法来处理这个问题。而且我没有找到关于在Node中使用BRPOPLPUSH来阻塞(与RPOPLPUSH相对)和等待的信息...或者其他类似的选项。(Pub/Sub在这里不可用...这是唯一的侦听器,并且它可能并不总是在侦听。)

以下是我正在做的简短要点:

var Redis = require('ioredis');
var redis = new Redis();

var redisLoop = function () {
    redis.rpoplpush('channel', 'channel-working').then(function (result) {
        if (result) {
            processJob(result); //do stuff

            //delete the item from the working channel, and check for another item
            redis.lrem('channel-working', 1, result).then(function (result) { });
            redisLoop();
        } else {
            //no items, wait 1 second and try again
            setTimeout(redisLoop, 1000);
        }
    });
};

redisLoop();

我感觉我可能忽略了什么非常显然的东西。谢谢!


你能详细说明为什么发布/订阅模式不可行吗?当没有任何订阅者时,完全可以发布。你可以将推送工作到Redis的过程也作为发布。如果此应用程序已订阅,则会被唤醒。如果没有订阅,什么都不会发生。 - Wander Nauta
从我所看到的情况来看(没有更复杂的解决方法),如果发布了一条消息但没有订阅者,那么这条消息就会丢失。这更像是一个消息队列模型,只有一个监听器——最重要的是通道中的项目一直保持存在,直到被弹出,无论是几秒钟还是几天(如果进程死亡、机器离线等)。 - XediDC
没错,消息丢失了。这就是为什么你还要发布:工作生成应用程序会将工作放入队列中,然后才会 PUBLISH 一些东西(比如一个空字符串),以便在在线但处于睡眠状态时唤醒该应用程序。 - Wander Nauta
啊,好的,我明白你的意思了。是的,我读过一篇关于使用发布+队列方法来实现更高可靠性的文章。虽然我无法完全控制上游端,但我会尝试解决这个问题。谢谢! - XediDC
1个回答

5
< p > BRPOPLPUSHNode 中不会阻塞,它会在 client 中阻塞。在这种情况下,我认为这正是你需要摆脱轮询的方法。

var Redis = require('ioredis');
var redis = new Redis();

var redisLoop = function () {
    redis.brpoplpush('channel', 'channel-working', 0).then(function (result) {
        // because we are using BRPOPLPUSH, the client promise will not resolve
        // until a 'result' becomes available
        processJob(result);

        // delete the item from the working channel, and check for another item
        redis.lrem('channel-working', 1, result).then(redisLoop);
    });
};

redisLoop();

请注意,redis.lrem 是异步的,因此您应该使用 lrem(...).then(redisLoop) 确保在成功从 channel-working 中删除项目后,您的下一个刻度才会执行。


谢谢!我觉得我可能接近了那个......但在到达之前又走了另一条路。现在看我的简化示例和你写的东西,它看起来非常明显。 :) - XediDC
3
没问题!顺便说一下,在这里 Node 中不能有 I/O 阻塞是很重要的。你可以同时进行其他工作。但是,如果你尝试同时重用相同的“redis”客户端调用 Redis,则你的循环会产生干扰。我提到这点是因为最近在一个项目中遇到了这个问题并意识到我需要第二个“非阻塞”的客户端来运行命令,而第一个客户端则处于阻塞状态。 - Igor Raush

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接