Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
27k stars 3.85k forks source link

Cannot connect to replicaSet with secondary only #3209

Closed PhilippKrone closed 9 years ago

PhilippKrone commented 9 years ago

Hello,

I have a replicaSet consisting out of 2 data-holding nodes (priority 1 and priority 2) and 1 arbiter. Once I take down the priority 1 node and the arbiter - as expected - the third node (formerly primary) is becoming a secondary.

I'm now trying to connect to the replicaSet via node.js/mongoose with my standard connection string, which is working as long as 2 / 3 are up and running:

mongodb://user:pass@ip:port,ip:port/DB

and the following options:

var options = {
  server: {
    socketOptions: {
      keepAlive: 1,
    },
  },
  replset: {
    auto_reconnect: true,
    socketOptions: {
        keepAlive: 1,
        connectTimeoutMS: 5000,
    },
    strategy: 'ping',
    read_secondary: true,
    readPreference: 'nearest',
    slaveOk: true,
    safe: {w:"majority", j:1, wtimeout: 10000}
  }
};

However, I get back:

error: Connection error to mongoose: MongoError: no valid seed servers in list

rs.status() on the secondary tells me that 2 servers have a health:0 and one server (itself) has a health:1. So I'd expect that node / mongoose can connect to the remaining server and read from it.

Any idea what the issue might be?

Regards Philipp

vkarpov15 commented 9 years ago

Which servers are you listing in your connection string? Could be that your connection string only includes the 2 servers that you took down.

PhilippKrone commented 9 years ago

@vkarpov15 :) I've thought about that as well, but the moment I change my connection string from:

mongodb://user:pass@ip1:port1,ip2:port2/DB?replicaSet=myReplicaSet

to

mongodb://user:pass@ip2:port2/DB

, so essentially connecting to the running server only without specifying a replicaSet, it is able to connect.

vkarpov15 commented 9 years ago

I don't understand. That means that you now have a connection to a standalone mongodb instance, which isn't what you want. How do ip1, etc. map to the servers in your original example?

PhilippKrone commented 9 years ago

@vkarpov15 OK, let me summarize my issue:

Architecture

I have a replica set consisting out of 3 nodes:

Connection string

I'm connecting via the following connection string:

mongodb://user:pass@IP1:port,IP2:port/DB?replicaSet=myReplicaSet

with the following connection settings

var options = {
  server: {
    socketOptions: {
      keepAlive: 1,
    },
  },
  replset: {
    auto_reconnect: true,
    socketOptions: {
        keepAlive: 1,
        connectTimeoutMS: 5000,
    },
    strategy: 'ping',
    read_secondary: true,
    readPreference: 'nearest',
    slaveOk: true,
    safe: {w:"majority", j:1, wtimeout: 10000}
  }
}

This is working just fine without any issue.

Issue (failover test)

During my failover tests, I'm shutting down IP1 (primary) and IP3 (arbiter), which makes IP2 the only node in the replica set and as it has no majority, it's becoming a secondary. So far, so good.
However, when I'm now trying to connect via node/mongoose again, I'm getting the following error:

Connection error to mongoose: MongoError: no valid seed servers in list

As a first analysis, I was trying to connect to the remaining server (IP2) without specifying the replicaSet in the connection URL:

mongodb://user:pass@IP2:port/DB

and this is working fine. However, this is not what I want obviously.

Question

Why is the connection to the replicaSet using the "correct connection url" not working, resulting in the "no valid seed servers in list" error?

vkarpov15 commented 9 years ago

Try setting the replSet.connectWithNoPrimary option. It looks like the mongodb driver refuses to do initial connection if it can't find a primary by default

PhilippKrone commented 9 years ago

@vkarpov15 thanks, that has worked! Sorry that I did not find that myself in the official docu - I was looking at various places in the official docu, but not in the document you've shown me.

PhilippKrone commented 9 years ago

@vkarpov15 sorry to open that again, but since using the mentioned parameter, I regulary get the following exception:

error: uncaughtException: self.isDead is not a function date=Fri Jul 31 2015 09:02:05 GMT+0200 (CEST), pid=25875, uid=501, gid=20, cwd=/Users/philippkrone/Documents/startup/development/myProject-backend, execPath=/usr/local/bin/iojs, version=v2.2.1, argv=[/usr/local/bin/iojs, /Users/philippkrone/Documents/startup/development/myProject-backend/main.js], rss=106340352, heapTotal=76279040, heapUsed=32140824, loadavg=[1.9990234375, 1.880859375, 1.8447265625], uptime=128215, trace=[column=44, file=/Users/philippkrone/Documents/startup/development/myProject-backend/node_modules/mongoose/node_modules/mongodb/lib/cursor.js, function=Cursor.nextObject [as next], line=407, method=nextObject [as next], native=false, column=18, file=/Users/philippkrone/Documents/startup/development/myProject-backend/node_modules/mongoose/node_modules/mongodb/lib/topology_base.js, function=Store.execute, line=71, method=execute, native=false, column=31, file=/Users/philippkrone/Documents/startup/development/myProject-backend/node_modules/mongoose/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/replset.js, function=null._onTimeout, line=888, method=_onTimeout, native=false, column=15, file=timers.js, function=Timer.listOnTimeout, line=89, method=listOnTimeout, native=false], stack=[TypeError: self.isDead is not a function,     at Cursor.nextObject [as next]

is this somehow connected?

vkarpov15 commented 9 years ago

I doubt that's a related issue. Can you open up a separate issue for that?

jsguy commented 7 years ago

Just thought I'd mention, I had this issue in Mongoose 4.5.3 - once I updated to 4.10.6, I did not need to change any settings, ie: I didn't set replSet.connectWithNoPrimary.