猫鼬 startSession() 挂起

Lah*_*ima 5 mongoose mongodb node.js

我正在使用 mongoose 通过我的 nodejs 服务器连接到我的 Mongodb Atlas 集群。

有一个特定的操作是作为一个事务完成的。需要mongoose.startSession()调用Mongoose来启动事务。在极少数情况下,此mongoose.startSession()调用会无限期挂起。没有特定的方法可以重现这一点。

log.info('starting lock session');
const mongoSession = await mongoose.startSession();
log.info('lock session started');
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,starting lock session.会被记录,但lock session started在出现问题时不会被记录。

我像下面这样连接到数据库:

const dburl = 'mongodb+srv://myuser:mypassword@myapp.mongodb.net/mydb?retryWrites=true&w=majority';
mongoose.connect(dburl, {useNewUrlParser: true}, err => {
    if (err) {
        log.warn('Error occurred when connecting to database. ' + err);
    }
});
Run Code Online (Sandbox Code Playgroud)

这可能是什么原因?这可能是由于数据库有问题吗?有什么办法可以进一步解决这个问题吗?

Lah*_*ima 4

这看起来像是猫鼬中的一个错误,我向猫鼬报告了它,但仍然没有得到回应。

https://github.com/Automattic/mongoose/issues/8325

我编写了以下函数,我可以用它来等待猫鼬连接准备好后再调用startSession(),它解决了我的问题。

function waitForMongooseConnection(mongoose) {
    return new Promise((resolve) => {
        const connection = mongoose.connection;
        if (connection.readyState === 1) {
            resolve();
            return;
        }
        console.log('Mongoose connection is not ready. Waiting for open or reconnect event.');
        let resolved = false;
        const setResolved = () => {
            console.log('Mongoose connection became ready. promise already resolved: ' + resolved);
            if (!resolved) {
                console.log('Resolving waitForMongooseConnection');
                resolved = true;
                resolve();
            }
        };
        connection.once('open', setResolved);
        connection.once('reconnect', setResolved);
    });
}
Run Code Online (Sandbox Code Playgroud)

通过上述功能,我可以像下面这样启动会话:

log.info('starting session');
await waitForMongooseConnection(mongoose);
const mongoSession = await mongoose.startSession();
log.info('session started');
Run Code Online (Sandbox Code Playgroud)

请注意,我必须关闭useUnifiedTopology。否则,不会调用“重新连接”。

mongoose.connect(config.db, {useNewUrlParser: true, useUnifiedTopology: false}, err => {
    if (err) {
        log.warn('Error occurred when connecting to database. ' + err);
    }
});
Run Code Online (Sandbox Code Playgroud)