2

I saw a lot of posts and articles about this alert on MongoDB Atlas ("Connections % of configured limit has gone above 80"), but couldn't figure out how to solve it in my Next.js application.

I create my db connection outside the handler function. I used a middleware withDatabase.js:

const client = new MongoClient(process.env.MONGODB_URI, { 
    useNewUrlParser: true, 
    useUnifiedTopology: true 
});

const addDbToRequest = (handler, req, res) => {
    req.db = req.connection.db("MYDBNAME");
    return handler(req, res);
};

const withDatabase = handler => async (req, res) => {
    if (!client.isConnected()) {
        await client.connect();
    }
    req.connection = client;
    return addDbToRequest(handler, req, res);
};

export default withDatabase;

This middleware wraps the API endpoint handler.

Now, if I close the connection on every API handler when it finishes, like this:

    const { connection } = req;
    if (connection) {
        connection.close();
    }

Than, I'm getting an error on the second request to the same api handler:

MongoError: Topology is closed, please connect

And if i'm not closing the connection, i'm getting this alert (after a short time of use) to my email:

Connections % of configured limit has gone above 80

What is the best practices to work with MongoDB Atlas in a Next.js application?

Thanks!

user3343396
  • 517
  • 1
  • 8
  • 22

2 Answers2

3

The connection should be reused for the following reasons:

  1. Opening and closing DB connections on every API request is slow.
  2. It's hardly scalable. Assuming you're making a few API requests simultaneously per user, you will reach the same connections limit quickly when the app gets more users.

How do I manage MongoDB connections in a Node.js web application?

Default MongoClient configuration has maximum number of connections per pool (poolSize) set to 5. So, you shouldn't see more than ~5 connections in MongoDB Atlas if you have only one app instance running and checking whether a client is connected already, like you do.

if (!client.isConnected()) {
  await client.connect();
}

Note, that Next.js "restarts" on every request in the development mode (next dev) and it seems it affects MongoClient cache and creates many connections. However in production mode, you shouldn't experience this issue.

Nikolai Kiselev
  • 4,499
  • 2
  • 18
  • 28
  • so the problem is the develop mode, because i'm not closing the connection.. – user3343396 May 01 '20 at 08:59
  • 1
    what about 'Fast Refresh'? Then in develop mode every code change will trigger new connections which will hit the MongoDB Atlas limit quickly – Se7enDays Sep 10 '20 at 11:51
  • Until I learned of the poolSize configuration this did not make any sense. As the MongoDb Guide states `poolSize: Specifies the maximum size of the instance connection pool.` So when you execute `client.connect()` this is setting up a connection 'pool' (which can consist of multiple connections). The developers probably should have worded the `connect` function differently (maybe 'ICP' for instance connection pool) so users are not under the impression that it is simply setting up a single connection to the database. MongoDb Atlas does not seem to track connection pools, only connections. – w. Patrick Gale Jul 08 '21 at 04:36
0

To fix the max connections reached issue in Next's dev mode, I found writing the reused/cached client object to the global Node object allowed it to persist between refreshes.

const MongoClient = require('mongodb').MongoClient;

async function useMongoClient() {
  if (!this.client) {
    this.client = await MongoClient.connect(process.env.MONGODB_URI, {
      useUnifiedTopology: true,
    });
  }

  return this.client;
}

module.exports = useMongoClient;
atomiks
  • 584
  • 5
  • 9
  • in my env "this" comes up undefined and i cannot attach any params to it... "global" is a thing, but i tried to create "global.cachedDB" and it always comes up undefined. – K.H. B Apr 16 '21 at 13:57