Nodejs with MongoDB - Number of Opened Connections Keep on Increasing with Mongoose Library

June 01, 2022

Introduction

In one of my Nodejs app, I was using Mongoose to talk to MongoDB. I have used some event handling that whenever connection got disconnected, it tries to re-connect. But, over the period of time, MongoDB started complaining that the number of opened connections are getting very high. It was strange as I was not using much connections.

Old Code

const mongoose = require('mongoose');

class DatabaseController {

    //...some code

    initialize() {
        const db = mongoose.connection;

        db.on('connecting', () => {
            logger.log('info','connecting to MongoDB...');
        });

        db.on('connected', () => {
            logger.log('info','MongoDB connected!');
        });
        db.on("disconnected", () => {
            logger.log('error','MongoDB disconnected!');
        });
        db.once('open', () => {
            logger.log('info','MongoDB connection opened!');
        });
        db.on('reconnected', () => {
            logger.log('info','MongoDB reconnected!');
        });
        db.on("close", () => {
            logger.log('info','MongoDB connection closed!');
        });
        db.on("error", (error) => {
            logger.log('error','MongoDB error!', error);
        });

        const dbURI = "...your-connection";
        return mongoose.connect(dbURI, { 
            useUnifiedTopology: true, 
            useNewUrlParser: true, 
            useCreateIndex: true, 
            useFindAndModify: false, 
            serverSelectionTimeoutMS: 60000
        });
    }
}

Need to Close MongoDB Connections Explicitly

Earlier, I was even re-connecting on disconnect event. So, it was calling a connect request again.

Even when you are stopping your app in a normal way or your app crashes. It will not close your DB connections.

Goto your MongoDB instance, open mongo shell:

> db.serverStatus().connections
{
	"current" : 12,
	"available" : 838859,
	"totalCreated" : 27,
	"active" : 1,
	"exhaustIsMaster" : 0,
	"exhaustHello" : 0,
	"awaitingTopologyChanges" : 0
}

Look at the current number of connections. Now, with this code. You are not closing connections. And, this will result in lot of open connections at DB side.

You might think of why would DB is not closing stale connections. The reason DB administrators don’t do this, is that they don’t have any idea about the lifecycle of a db script. Some db script might take 1-2 hours to fetch results. So, they do not clean the connections.

Its your responsibility to close the connections.

Solution

Lets try to close the connections:

const mongoose = require('mongoose');

class DatabaseController {

    //...some code

    initialize() {
        const db = mongoose.connection;

        db.on('connecting', () => {
            logger.log('info','connecting to MongoDB...');
        });

        db.on('connected', () => {
            logger.log('info','MongoDB connected!');
        });
        db.on("disconnected", () => {
            logger.log('error','MongoDB disconnected!');
        });
        db.once('open', () => {
            logger.log('info','MongoDB connection opened!');
        });
        db.on('reconnected', () => {
            logger.log('info','MongoDB reconnected!');
        });
        db.on("close", () => {
            logger.log('info','MongoDB connection closed!');
        });
        db.on("error", (error) => {
            logger.log('error','MongoDB error!', error);
        });

        // to prevent connection leaks we close connections on any restart
        ['SIGINT', 'exit', 'SIGTERM', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'unhandledRejection'].forEach((sig_event) => {
            process.on(sig_event, (err) => {
                logger.log('error', `Disconnecting mongodb for event: ${sig_event}`);
                if (err) {
                    logger.log('error', err);
                }
                mongoose.disconnect();
            });
        });

        const dbURI = "...your-connection";
        return mongoose.connect(dbURI, { 
            useUnifiedTopology: true, 
            useNewUrlParser: true, 
            useCreateIndex: true, 
            useFindAndModify: false, 
            serverSelectionTimeoutMS: 60000
        });
    }
}

Now, we are closing the db connections on app closing events:

  • SIGINT for ctrl+c
  • exit when app is closing

You might also handle two more events:

  • uncaughtException for unhandled exceptions
  • unhandledRejection for unhandled promise rejections

Hope it helps.


Similar Posts

Latest Posts