nodejs推送订阅redis的通知

时间:2014-06-15 22:11:51

标签: node.js long-polling

仅限登录用户,我想以某种方式通知他们,如果他们有任何例如新通知。

例如,假设某个成员向他们发送了私人消息,我想告诉用户他们有一条要查看的新消息(假设他们没有刷新页面)。

使用Nodejs和redis,我将如何做到这一点?

注意:我只需要nodejs向用户发送一个小json,说他们有新消息。

我正在考虑的工作流程如下:

    1. user is logged in, a new message is sent to them.
    2. somehow using nodejs and redis and long-polling, nodejs communicates back to the logged in users browser they have a pending message.
    3. when nodejs sends this push notification, I then call another javascript function that will call a rest service to pull down additional json with the message.

我正在将nodejs集成到现有的应用程序中,所以我希望尽可能简单地使用nodejs来负责通知而不做任何额外的逻辑。

有人可以概述我应该如何解决这个问题吗? 我应该以某种方式使用redis http://redis.io/topics/pubsub吗? 即使在阅读了有关它的页面后,我也不确定它是如何工作的。

2 个答案:

答案 0 :(得分:5)

如果要将node服务集成到现有应用程序中,我宁愿使用某种消息传递系统将来自该应用程序的消息传递给node而不是数据库,甚至是内存数据库。 为了清晰,我假设您可以使用rabbitmq。如果你确实需要使用redis,你只需要找到一种方法来使用它的发布而不是rabbitmq发布和相应的节点端订阅,但我认为整体解决方案是完全相同的。

您需要以下模块:

  • rabbitmq服务器(安装复杂性与redis相同)
  • 外部应用程序中的
  • rabbitmq库发送消息,支持大多数语言
  • {li> rabit.js node模块订阅消息或与外部应用程序通信
  • socket.io node模块,用于在node服务器和客户端之间建立实时连接

我还假设您的外部应用程序和node服务器都可以访问某些共享数据库(可以是redis),其中存储了node客户端会话信息(例如{{1} } redis-session-store)。这将允许使用node来验证邮件的用户,会话中的用户是否已登录以及是否需要向某些用户发送通知(由外部应用程序)。

这就是你的堆栈的样子(未抛光):

sessionId中定义发布商,通知您的外部应用程序需要开始/停止发送给定node的消息。我将假设对于给定的sessionId,可以从共享数据库中恢复用户信息(sessionId或外部应用程序),并且可以验证用户(这里为了简单起见,检查{{1} }})。还要定义订阅者以收听用户的传入消息:

node

定义从session.authenticated_user服务器到客户端的var context = require('rabbit.js').createContext(); var pub = context.socket('PUB'); var sub = context.socket('SUB'); 连接。一旦客户的网页被(重新)加载并且socket.io被调用,将执行以下代码(参见答案结尾处的clinet侧)。在建立新连接时,验证用户是否已登录(意味着其凭据在会话中),注册套接字处理程序并向外部应用程序发布通知以开始为此node发送消息。此处的代码假定登录/注销时页面重新加载(因此新的io.connect()会话)。如果不是这种情况,只需从客户端向sessionId发出相应的socket.io消息,并按照与新连接相同的方式在下面的方法中注册处理程序(这超出了这个例子的范围):

socket.io

将订阅者连接到node交换机以捕获消息并将其发送给客户端:

var sessionStore = undefined; // out-of-scope: define redis-session-store or any other store

var cookie = require("cookie"),
    parseSignedCookie = require('connect').utils.parseSignedCookie;

// will store a map of all active sessionIds to sockets
var sockets = {};

// bind socket.io to the node http server
var io = require('socket.io').listen(httpServer);

// assumes some config object with session secrect and cookie sid
io.sockets.on("connection", function(socket) {
    if (socket.handshake.headers.cookie) {
        var cks = cookie.parse(socket.handshake.headers.cookie);
        var sessionId = parseSignedCookie(cks[config.connectSid], config.sessionSecret);

        // retrieve session from session store for sessionId
        sessionStore.get(sessionId, function(err, session) {
            // check if user of this session is logged in, 
            // define your elaborate method here
            if (!err && session.authenticated_user) { 
                // define cleanup first for the case when user leaves the page
                socket.on("disconnect", function() {
                    delete sockets[sessionId];
                    // notify external app that it should STOP publishing
                    pub.connect('user_exchange', function() {
                        pub.write(JSON.stringify({sessionId: sessionId, action: 'stop', reason: 'user disconnected'}), 'utf8');
                    });
                });

                // store client-specific socket for emits to the client
                sockets[sessionId] = socket;

                // notify external app that it should START publishing
                pub.connect('user_exchange', function() {
                    pub.write(JSON.stringify({sessionId: sessionId, action: 'start'}), 'utf8');
                });
            }
        });
    }
});

最后你的客户端看起来大致如此(这里是Jade,但那只是因为我已经沿着这些线路拥有整个堆栈):

rabbitmq

答案 1 :(得分:1)

以下是Flickr关于如何使用NodeJS和Redis创建高度可用且可扩展的推送通知系统的非常好的解释。

http://code.flickr.net/2012/12/12/highly-available-real-time-notifications/