n8n-io / n8n

Free and source-available fair-code licensed workflow automation tool. Easily automate tasks across different services.
https://n8n.io
Other
47.54k stars 7.17k forks source link

MongoDB cannot connect on latest version of n8n (but works with older version) #4886

Open kimus opened 1 year ago

kimus commented 1 year ago

Describe the bug After upgrading my docker container to ‘latest’ version (0.206.1) of n8n the MongoDB connections stopped to work. And with an older version (0.173.1) works fine.

image It seams that it's ignoring my setting and trying to connect to the local docker-compose network?? Even the port is the 'default' and not what I've provided in the connection url.

To Reproduce Not sure why it’s getting the error, when the connections string is not the provided. I’m using something like: mongodb://user:pass@db02.s.example.com:27018/db-prd?authSource=admin&readPreference=secondary

Expected behavior Should connect has normal. Like older versions does.

Environment (please complete the following information):

luizeof commented 1 year ago

@Joffcom same here ... doesn't work with connection string or values

netroy commented 1 year ago

Are you able to add and test new credentials?

kimus commented 1 year ago

@netroy Adding or editing an existing one will give me the same error:

Couldn’t connect with these settings 
connect ECONNREFUSED 192.168.149.173:27017
kimus commented 1 year ago

So, I've found out that 192.168.149.173:27017 is the primary member of the replica set. It's an internal server, so, it should not be reached directly and should not connect.

After some debugging I've found out that the error is:

MongoServerSelectionError: connect ECONNREFUSED 192.168.149.173:27017

Strangely, if I do a docker-compose exec n8n /bin/shand do:

> cd /usr/local/lib/node_modules/n8n
> MONGO_URI='... same connection string ... ' node

const { MongoClient } = require('mongodb');
const uri = process.env.MONGO_URI;
const client = new MongoClient(uri);
await client.connect();
await client.db().admin().listDatabases();
await client.db().collection('User').find({ username: /^teste/}).limit(1).toArray()

it works fine :-(

kimus commented 1 year ago

So, in /usr/local/lib/node_modules/n8n there is a different mongodb package version:

> grep '"version":' node_modules/mongodb/package.json
  "version": "3.7.3",

Then in /usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base:

> grep '"version":' node_modules/mongodb/package.json
  "version": "4.12.1",

And so, trying this:

> cd /usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base
> MONGO_URI='... same connection string ... ' node

const { MongoClient } = require('mongodb');
const client = new MongoClient(process.env.MONGO_URI);
Uncaught [MongoServerSelectionError: connect ECONNREFUSED 192.168.149.173:27017] {
  reason: TopologyDescription {
    type: 'ReplicaSetNoPrimary',
    ...

gives me the same error has the n8n instance. So it's an connection error related with the latest version of mongodb package.

Joffcom commented 1 year ago

Hey @kimus & @luizeof,

How do you both have MongoDB running and what version are you using? I have did a quick test yesterday and it is working for me on 0.206.1 with MDB 5.0.6 running in Docker. The string I have used is the one that Compass built out for me.

image

Based on what is in here already it could be something in the connection string that needs to be updated but if we can reproduce it we will be able to work out the fix for it.

kimus commented 1 year ago

Hi @Joffcom ,

The problem is related with this being a replicaSet. and not a normal MongoDB instance. And so, I could describe my setup:

The connection string is something like: mongodb://user:pass@secondary.public.io:27018/?authSource=admin&readPreference=secondary The replica set is configured with the following members (all in a private network):

[
    "db01.private.io:27017",    // primary
    "db02.private.io:27018",    // secondary
    "db03.private.io:27018" // arbiter
]

So, the secondary member (secondary.public.io) has an public ip and the port 27018 is opened. And it works fine with the mongodb driver v3 but not with v4.

netroy commented 1 year ago

So, in /usr/local/lib/node_modules/n8n there is a different mongodb package version:

> grep '"version":' node_modules/mongodb/package.json
  "version": "3.7.3",

Then in /usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base:

> grep '"version":' node_modules/mongodb/package.json
  "version": "4.12.1",

The 3.x version of the mongodb is being pulled in by typeorm, but it's not being used in the MongoDB node.

So it's an connection error related with the latest version of mongodb package.

Yeah, my suspicion is that somehow the older format of your connection string isn't compatible with the 4.x mongodb driver, just as you said.

Joffcom commented 1 year ago

Hey @kimus,

Could you try the below (add +srv) and let me know if it works? I set up an Atlas instance and if I don't include that one part it won't connect.

mongodb+srv://user:pass@secondary.public.io:27018/?authSource=admin&readPreference=secondary

kimus commented 1 year ago

@Joffcom, can you test this?

version: "3"

services:
  mongo-primary:
    image: bitnami/mongodb:4.0
    restart: always
    environment:
      - MONGODB_REPLICA_SET_MODE=primary
      - MONGODB_ADVERTISED_HOSTNAME=mongo-primary
      - MONGODB_REPLICA_SET_KEY=repls0
      - MONGODB_ROOT_PASSWORD=s3cr3tp4ss

  mongo-secondary:
    image: bitnami/mongodb:4.0
    depends_on:
          - mongo-primary
    ports:
      - "27018:27017"
    restart: always
    environment:
      - MONGODB_REPLICA_SET_MODE=secondary
      - MONGODB_ADVERTISED_HOSTNAME=mongo-secondary
      - MONGODB_REPLICA_SET_KEY=repls0
      - MONGODB_INITIAL_PRIMARY_HOST=mongo-primary
      - MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017
      - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=s3cr3tp4ss

  mongo-arbiter:
    image: bitnami/mongodb:4.0
    depends_on:
      - mongo-primary
    environment:
      - MONGODB_REPLICA_SET_MODE=arbiter
      - MONGODB_ADVERTISED_HOSTNAME=mongo-arbiter
      - MONGODB_REPLICA_SET_KEY=repls0
      - MONGODB_INITIAL_PRIMARY_HOST=mongo-primary
      - MONGODB_INITIAL_PRIMARY_PORT_NUMBER=27017
      - MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD=s3cr3tp4ss

volumes:
  mongodb_master_data:
    driver: local
kimus commented 1 year ago

Hey @kimus,

Could you try the below (add +srv) and let me know if it works? I set up an Atlas instance and if I don't include that one part it won't connect.

mongodb+srv://user:pass@secondary.public.io:27018/?authSource=admin&readPreference=secondary

@Joffcom SRV is a way to specify a single hostname that resolves to multiple host names. When using SRV, the driver conducts an SRV lookup to get the actual names of all of the hosts. The opposite of I want to achieve here. And it does not allow me to add a port on the connection string either.

Joffcom commented 1 year ago

@kimus that is a shame, it managed to get Atlas working for me and was the recommended string when using newer versions of the MongoDB driver.

It could be a case of going back to the driver documentation to see what has changed, I have just spotted the compose file I will give that a bash this afternoon and see what I can find. I am not convinced this is directly an n8n issue at the moment though.

Joffcom commented 1 year ago

@kimus just a quick update, If I use that setup with Compass I get a similar error with the wrong port being used.

image

I will continue digging later today but it looks like there could be more to this as the MongoDB provided tool also doesn't appear to work with that setup.

kimus commented 1 year ago

@Joffcom you can connect in MongoDB compass with the full connection string like this: mongodb://root:s3cr3tp4ss@localhost:27018/?readPreference=secondary&directConnection=true

And yes, I've tried to add directConnection=true in nodejs mongodb v4 and does not work, it gives an error not master and slaveOk=false.

And I can add that I'm using other tools to connect to this MongoDB replica set and all are working fine with the same connection string. In languages like Java and Python. Eventually we will figure this out :-)

kimus commented 1 year ago

I've created a test case at https://github.com/kimus/mongodb-replicaset

Joffcom commented 1 year ago

Hey @kimus,

I am now able to connect from n8n to MongoDB using the string you provided which also works in Compass (thanks for that). It looks like the issue is with our credential test, For the test we use client.db().admin().listDatabases() which seems to throw an error when ran on the secondary but if you ignore the error and go to use the credential it appears to work for reading collection data (in my test I have used the config collection).

I did notice the secondaryOK option, Could be that we just need to set that as well but for now the above might get you up and running.

kimus commented 1 year ago

@Joffcom for newer versions of MongoDB the option secondaryOk has bean, or will be, changed because of the offensive term. Older MongoDB versions still have the older name slaveOk and that's why we are seeing the error not master and slaveOk=false.

Also, the MongoClient docs do explicitly state for slaveOk: "legacy option allowing reads from secondary, use readPrefrence instead". They also state that setting a readPreference overrides any slaveOk value. So, I'm guessing that there is a incompatible communication between the new versions of the MongoDB node driver and older MongoDB databases.

Joffcom commented 1 year ago

Hey @kimus,

Is that not why secondaryOK is an option now as a replacement? Did you try just using the node anyway to see if it works for you like it does for me?

kimus commented 1 year ago

@Joffcom yes, 'ignoring' that error it does do the query on n8n!

Joffcom commented 1 year ago

@kimus that is good news, So it will be something with that admin query to list databases in the credential test. There will be a better way we can handle that which I will look into later this week if I get chance.