【问题标题】:Mongoose findOneAndUpdate() blocking socket.io requests?Mongoose findOneAndUpdate() 阻塞 socket.io 请求?
【发布时间】:2019-03-08 03:22:06
【问题描述】:

我不确定是不是有什么我不明白的地方,或者有什么错误,但我就是想不通。基本上偶尔,我会从我的服务器向 API 发送一个请求,以获取一些信息,然后将其保存到我的数据库中,但是每当保存数据时,socket.io 请求就会被阻塞,并且只有当所有数据都被阻塞时已更新是当其他请求大量通过时。我知道他们被阻止了,因为我尝试在更新数据时每 100 毫秒发送一条聊天消息,并且只有当 API 中的最后一条信息被保存并且在它被保存时没有一条消息通过时,所有消息才通过保存。我怎样才能让它不阻止其他请求?

这是我测试时控制台输出的示例:

...
New chat message received
New chat message received
New chat message received
New chat message received
UPDATING 1455 ITEMS
UPDATED ALL PRICES, TOOK 3592
New chat message received
New chat message received
New chat message received
New chat message received
...

代码:

request('url')), (err, response, body) => {
        let items = JSON.parse(body);
        let startTime = new Date().getTime();
        console.log(`UPDATING ${items.prices.length} ITEMS`);

        for (let i = 0; i < items.prices.length; i++) {
            const item = items.prices[i];

            Prices.findOneAndUpdate({item: item.name}, {$set: {price: item.price, last_update: Date.now()}}, (err, res) => {
                if(!res){
                    newPrice = new Prices({
                        item: item.name,
                        price: item.price
                    });

                    newPrice.save((err, saved) => {
                        if (err) {
                            console.log(err);
                        }
                    })
                }

                if(i == items.prices.length - 1){
                    console.log(`UPDATED ALL PRICES, TOOK ${new Date().getTime() - startTime}`);                    
                }
            });
        }
});

不确定这是否会有所帮助,但这里是处理接收消息的代码:

socket.on('sendMessage', (data) => {
    User.findOne({id: socket.request.user.id}, (err, user) => {
        if (err) throw err;

        //Check if the user is muted and if not, proceed
        if(user.mutedUntil < Date.now()){
            User.findOneAndUpdate({id: socket.request.user.id}, {$set: {lastMessageDate: Date.now()}}, (err, dbUser) => {
                if (err) throw err;

                let parsed = ParseMessage(data.message);                     

                if(parsed.command === 'none'){
                    SendMessage(dbUser, socket, data);
                }else{
                    commandData = {parsed: parsed, socket: socket}
                    ExecuteChatCommand(commandData);
                }
            });
        }else{
            socket.emit('serverMessage', {
                type: 'error',
                title: 'You\'re muted',
                message: 'You are muted and can\'t chat until ' + user.mutedUntil
            });
            console.log('Muted user tried chatting');
        }
    });       
});

【问题讨论】:

    标签: node.js mongodb express mongoose socket.io


    【解决方案1】:

    您的for 循环正在执行阻塞,因为它是一个同步操作。

    您应该考虑改用 Promises。而不是 for 循环在 BlueBird 中使用 Promise.map or Promise.all 或在 ES6 中使用 Promise.all 来实现相同但以异步方式。

    对于您的查询,您可以使用 mongoose .exec() 将它们转换为成熟的 Promise。

    注意:您正在尝试在该 for 循环中查找和更新 1455 次...也许查看 Bluebird 中的 Promise.mapSeries,以便不会同时发送所有 Promise到 Mongo,但以串行方式

    【讨论】:

    • 尝试使用Promise.map,起初它没有任何区别,但是当我进一步研究时,我发现了concurrency选项,当我将它设置为1时似乎问题得到了解决,并且在更新我的数据库时其他请求没有被阻止。感谢您的帮助!
    猜你喜欢
    • 2011-07-07
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 2012-10-14
    • 2020-12-14
    • 2021-08-28
    • 2021-03-23
    相关资源
    最近更新 更多