实时通知 - 数据库轮询 - 最佳实践

时间:2017-04-22 12:25:56

标签: node.js mongodb notifications database

我正在向用户提供实时通知。

我正在讨论两个选项,并且在轮询数据库时无法确定哪种方法最佳。

(通过使用WebSockets传输通知。)

选项1 (当前):

我拥有所有登录用户的列表。 每1000毫秒,我检查数据库是否有新通知,如果有,我通过WS向适当的用户发送消息。

优点:

  • 此任务在资源上并不昂贵

缺点:

  • 在休息时间,每1分钟只有一个新通知,我无缘无故地轮询数据库60次。
  • 从某种意义上说,这不是实时的,因为要更新新通知需要1秒钟。如果它是一个聊天服务,1秒是一个很长的等待时间。

选项2:

创建一个钩子,无论何时保存(或删除)新通知,都会对db进行轮询。

优点:

  • 没有新通知时,不会对数据库进行轮询
  • 实际实时响应。

缺点:

  • 在高峰时段,当每秒生成多达10个新通知时,将经常轮询数据库,可能会阻止其对网站其他元素的响应时间。
  • 如果用户在生成通知时未登录,则通知更新将丢失(因为我仅为登录用户轮询数据库),除非我还在用户登录时执行计数以检索他们的他们离线时的通知。所以现在,我不仅在触发通知挂钩时轮询数据库,而且每次用户登录时都会轮询数据库。如果我每秒生成通知,每秒10次登录,我将最终每秒轮询我的数据库20次,这对于此任务来说非常昂贵。

您会选择哪个选项? 1,2?还是两个?为什么?

以下是我目前使用的代码(选项1)

var activeSockets = [] //whenever a user logs in or out, the array gets updated to only contain the logged-in users in any given moment

var count = function () {
    process.nextTick(function () {
        var ids = Object.keys(activeSockets) //the ids of all the logged in users
        //every user document has a field called newNotification that updates whenever a new notification is available. 0=no new notifications, >0=there are new notifications
        User.find({_id:{$in:ids}}).select({newNotifications:1}).lean().exec(function (err,users) {
            for(var i=0;i<users.length;i++) {
                var ws = activeSockets[String(users[i]._id)]
                if(ws!=undefined) {
                    if (ws.readyState === ws.OPEN) {
                        //send the ws message only if it wasn't sent before. 
                        if(ws.notifCount!=users[i].newNotifications) {
                            ws.send(JSON.stringify({notifications:users[i].newNotifications}));
                            activeSockets[String(users[i]._id)].notifCount = users[i].newNotifications
                        }

                    }
                    else {
                        //if the user logged out while I was polling, remove them from the active users array
                        delete activeSockets[String(users[i]._id)]
                    }
                }
            }
            setTimeout(function () {
                count()
            },1000)
        })
    })

}

选项2 的实施同样简单。而不是打电话

  

计数()

使用

  

的setTimeout()

我只在我的“新通知”,“删除通知”和“登录”挂钩中调用它。

代码

var activeSockets = [] //whenever a user logs in or out, the array gets updated to only contain the logged-in users in any given moment

var count = function () {
    process.nextTick(function () {
        var ids = Object.keys(activeSockets) //the ids of all the logged in users
        //every user document has a field called newNotification that updates whenever a new notification is available. 0=no new notifications, >0=there are new notifications
        User.find({_id:{$in:ids}}).select({newNotifications:1}).lean().exec(function (err,users) {
            for(var i=0;i<users.length;i++) {
                var ws = activeSockets[String(users[i]._id)]
                if(ws!=undefined) {
                    if (ws.readyState === ws.OPEN) {
                        //send the ws message only if it wasn't sent before. 
                        if(ws.notifCount!=users[i].newNotifications) {
                            ws.send(JSON.stringify({notifications:users[i].newNotifications}));
                            activeSockets[String(users[i]._id)].notifCount = users[i].newNotifications
                        }

                    }
                    else {
                        //if the user logged out while I was polling, remove them from the active users array
                        delete activeSockets[String(users[i]._id)]
                    }
                }
            }
        //setTimeout was removed
        })
    })

}

钩:

hooks = {
    notifications : {

        add: function () {
            count()
            //and other actions
        },
        remove: function () {
            count()
            //and other actions
        }
    },
    users: {
        logIn: function () {
            count()
            //and other actions
        }
    }
}

那么,您会选择哪个选项? 1,2?还是两个?为什么?

0 个答案:

没有答案