2

I am getting below error randomly. Here is my stack

  • App deployed on vercel is talking to Atlas mongodb (free tier)
  • Nodejs - 18.16.1
  • nextjs 13
  • mongodb package version - 5.8.1
ERROR   Unhandled Promise Rejection     {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"MongoServerSelectionError: connection timed out","reason":{"errorType":"MongoServerSelectionError","errorMessage":"connection timed out","reason":{"type":"ReplicaSetNoPrimary","servers":{},"stale":false,"compatible":true,"heartbeatFrequencyMS":10000,"localThresholdMS":15,"setName":"Cluster0-shard-0","maxElectionId":null,"maxSetVersion":null,"commonWireVersion":0,"logicalSessionTimeoutMinutes":null},"stack":["MongoServerSelectionError: connection timed out","    at Timeout._onTimeout (/var/task/node_modules/mongodb/lib/sdam/topology.js:278:38)","    at listOnTimeout (node:internal/timers:569:17)","    at process.processTimers (node:internal/timers:512:7)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: MongoServerSelectionError: connection timed out","    at process.<anonymous> (file:///var/runtime/index.mjs:1186:17)","    at process.emit (node:events:525:35)","    at emit (node:internal/process/promises:149:20)","    at processPromiseRejections (node:internal/process/promises:283:27)","    at process.processTicksAndRejections (node:internal/process/task_queues:96:32)"]}
[ERROR] [1692852863980] LAMBDA_RUNTIME Failed to post handler success response. Http response code: 400.
RequestId: 971d9da3-a51d-4511-a561-22d5702be848 Error: Runtime exited with error: exit status 128

When this error occurs, server responds with http 500 error code.

Can someone tell me why this would happen? Is it due to free tier of Atlas Mongodb?

Below code shows how I am connecting to mongodb. Clientpromise is being imported and then used to do db operations in other files.

import { MongoClient } from "mongodb";

//mongodb+srv://sjhfjhfjhf/ongodb.net/awesomedb?serverSelectionTimeoutMS=60000
const uri = process.env.MONGODB_URI;
const options = {
  //useUnifiedTopology: true,
  useNewUrlParser: true,
  serverSelectionTimeoutMS: 59000,
};

let client;
let clientPromise;

if (!process.env.MONGODB_URI) {
  throw new Error("Please add your Mongo URI to .env.local");
}

if (process.env.NODE_ENV === "development") {
  // In development mode, use a global variable so that the value
  // is preserved across module reloads caused by HMR (Hot Module Replacement).
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options);
    global._mongoClientPromise = client.connect();
  }
  clientPromise = global._mongoClientPromise;
} else {
  // In production mode, it's best to not use a global variable.
  client = new MongoClient(uri, options);
  clientPromise = client.connect();
}

// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;

Here is how I am firing the query


import { ObjectId } from 'mongodb';
import clientPromise from '../../lib/mongodb'
import { connectToDatabase, slugify } from './blog';

export async function saveAdToMongoDB(adObj) {
  try {
    const collection = (await clientPromise).db().collection("ads");  
    let catslug = slugify(adObj.businessCategory)
    let slug = slugify( adObj.businessName + "-" + adObj.city + "-" + catslug)
    adObj.slug = slug ;
    adObj.catslug = catslug;
    let advertisementObject = {...adObj, status:"pending",image:""}
    let result = await collection.insertOne(advertisementObject);
  } catch (err) {
    console.error("Failed to save ad to MongoDB:", err);
  } 
}

I upgraded mongodb and nextjs packages but it did not help. Most of other solutions on internet are talking about firewall and ip whitelisting. But I do not think that's causing the issue.

user2298124
  • 341
  • 2
  • 7
  • 1
    Have allowed access to your atlas cluster: https://www.mongodb.com/docs/atlas/security/ip-access-list/#add-ip-access-list-entries? – Robin Thomas Aug 24 '23 at 22:55
  • @robin-thomas I have given access to cluster from all ip addresses. If this was the issue, I would not have been able to connect to mongodb even once. Please note that this issue is happening randomly. – user2298124 Aug 25 '23 at 08:57
  • Can someone answer this question. it is mission critical issue for me!! – user2298124 Aug 25 '23 at 11:56

2 Answers2

1

It's a combination of limitations of free Atlas tier and Vercel hosting.

When you exhaust 500 connections quota, you get connection timeout. See this answer https://stackoverflow.com/a/76905054/1110423 for details.

Alex Blex
  • 34,704
  • 7
  • 48
  • 75
  • will the reason type in this case be `"type": "ReplicaSetNoPrimary",`? – dododo Aug 29 '23 at 10:59
  • 1
    @dododo, the root cause is "MongoServerSelectionError: connection timed out". It's just happened that the first thing the driver does is connects to the replicaset to find the primary member. I see your point and do agree that the answer is a bit speculative. Atlas monitoring of active connections at the time of the error would be the best proof. – Alex Blex Aug 29 '23 at 11:16
  • `MongoServerSelectionError: connection timed out` itself usually means not much without analyzing the cluster state in the error message. Idk, whether reason you mention about atlas limitation can generate `ReplicaSetNoPrimary` issue, I would not expect so, but hard to say for sure. I agree that we need more details, first of all from the server logs, to say something for sure. I've added my answer with some more details :) – dododo Aug 29 '23 at 11:42
  • 1
    @dododo, you're right. I wouldn't speculate if it wasn't for vercel + M0 Atlas combo and the fact that the OP is "getting below error randomly". These 2 just don't play together, and the symptoms are typical to the set up. – Alex Blex Aug 29 '23 at 12:46
0

I'm not a node developer, but this error looks more or less the same as in other languages, so:

The error reason is mentioned in this json (which is a driver side representation of the server state)

    {
        "errorType": "Runtime.UnhandledPromiseRejection",
        "errorMessage": "MongoServerSelectionError: connection timed out",
        "reason": {
            "errorType": "MongoServerSelectionError",
            "errorMessage": "connection timed out",
            "reason": {
                "type": "ReplicaSetNoPrimary",
                "servers": {},
                "stale": false,
                "compatible": true,
                "heartbeatFrequencyMS": 10000,
                "localThresholdMS": 15,
                "setName": "Cluster0-shard-0",
                "maxElectionId": null,
                "maxSetVersion": null,
                "commonWireVersion": 0,
                "logicalSessionTimeoutMinutes": null
            },
            "stack": ["MongoServerSelectionError: connection timed out", "    at Timeout._onTimeout (/var/task/node_modules/mongodb/lib/sdam/topology.js:278:38)", "    at listOnTimeout (node:internal/timers:569:17)", "    at process.processTimers (node:internal/timers:512:7)"]
        },
        "promise": {},
        "stack": ["Runtime.UnhandledPromiseRejection: MongoServerSelectionError: connection timed out", "    at process.<anonymous> (file:///var/runtime/index.mjs:1186:17)", "    at process.emit (node:events:525:35)", "    at emit (node:internal/process/promises:149:20)", "    at processPromiseRejections (node:internal/process/promises:283:27)", "    at process.processTicksAndRejections (node:internal/process/task_queues:96:32)"]
    }

The key point is here ReplicaSetNoPrimary. This error type says that at the time when error had happened, the driver didn't see any primary which made impossible any writing. So the MongoServerSelectionError error is expected.

What you can do:

  1. Try any "read" operation with enabled reading from secondaries via adding &readPreference=secondaryPreferred to the connection string. This option will allow you to use secondaries for reading.
  2. Enable useUnifiedTopology: true,. I'm not 100% confident what is this option about, you can read about it here. but I assume it might allow more correct/modern server selection handling.
  3. Check server logs and what happened at the error time there. You use mongodb+srv in the connection string. I assume you use Mongo Atlas. If so, then you can check atlas logs to see what server is the primary when the error happens. It might be that no primary elected at the error time. It will explain the driver error, then you will need investigate the server behavior, but I would defer further investigation steps until you will provide the results of what I mentioned above.
dododo
  • 3,872
  • 1
  • 14
  • 37