0

I have a NextJs app built with mongodb database.
I was surprised to see that I quickly almost reached the threshhold of maximum connections:
enter image description here
This app used to be built with node and react and this was never the case.
But the logic of connecting to the database has changed.
I have this function that connects to the database:

// lib/mongodb.ts
import mongoose from "mongoose";

// #TODO
// I tried putting this in types/global.d.ts
// But, I kept getting the mongoose global error
// So I brought it here
// Not sure if it makes sense to keep this here
declare global {
  var mongoose: {
    conn: any;
    promise: Promise<any> | null;
  };
}

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
  throw new Error("Please define the MONGODB_URI environment variable");
}

let cached = global.mongoose;

if (!cached) {
  // conn: The established connection
  // promise: Ongoing connection attempt
  /**
     * cached.promise: Prevents multiple concurrent connection attempts during the first request when the connection is not yet established.
       cached.conn: Efficiently returns the active connection after it has been established.
     */
  cached = global.mongoose = { conn: null, promise: null };
}

async function connectToDatabase() {
  /**
   * By storing the established connection in cached.conn, subsequent requests can
   * skip the connection process below entirely, leading to faster response times.
   */
  if (cached.conn) {
    return cached.conn;
  }

  /**
   * By checking cached.promise, we prevent redundant connection attempts.
   * If a connection attempt (promise) has already been made, we don't need to initiate
   * another one, we can reuse it, thus avoiding unnecessary load on the database.
   */
  if (!cached.promise) {
    /**
     * The connection promise is stored in cached.promise so that any subsequent requests made
     * before the connection resolves can await the same promise, preventing redundant connection
     *  attempts.
     */
    cached.promise = mongoose
      .connect(MONGODB_URI as string)
      .then((mongoose) => {
        return mongoose;
      })
      .catch((error) => {
        console.error("🚀 ~ Error connecting to MongoDB:", error);
        throw error; // Re-throw the error after logging
      });
  }

  try {
    cached.conn = await cached.promise;
  } catch (error) {
    throw error;
  }

  return cached.conn;
}

export default connectToDatabase;

And I call it with every query:

export async function GET(request: Request) {
  const searchParams = await request.json();
  await connectToDatabase();

  try {
    const results = await searchInstructors(searchParams);
    return NextResponse.json(results);
  } catch (error) {
    return NextResponse.json({ error: "Failed to fetch instructors" }, { status: 500 });
  }
}

Am I doing something wrong?

2

1 Answer 1

1

In your current implementation:

  1. You're calling connectToDatabase() in every API route handler
  2. While you have connection caching logic, there might be issues with:
    • Connection cleanup
    • Serverless function behavior
    • Proper mongoose configuration
import mongoose from 'mongoose';

declare global {
  var mongoose: {
    conn: typeof mongoose | null;
    promise: Promise<typeof mongoose> | null;
  };
}

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
  throw new Error('Please define the MONGODB_URI environment variable');
}

let cached = global.mongoose;

if (!cached) {
  cached = global.mongoose = { conn: null, promise: null };
}

async function connectToDatabase() {
  if (cached.conn) {
    return cached.conn;
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false, // Disable mongoose buffering
      serverSelectionTimeoutMS: 5000, // Timeout after 5s instead of 30s
      socketTimeoutMS: 45000, // Close sockets after 45s of inactivity
      maxPoolSize: 10, // Maximum number of sockets in the connection pool
      minPoolSize: 1, // Minimum number of sockets in the connection pool
    };

    cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
      return mongoose;
    });
  }

  try {
    cached.conn = await cached.promise;
  } catch (e) {
    cached.promise = null;
    throw e;
  }

  return cached.conn;
}

export default connectToDatabase;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.