Repository navigation
Description
Issue Description
When using parse-server 2.7.2 with a mongodb geographically seperated replicaset, using readPreference=nearest on the URI(or in databaseOptions) is not working. When setting mongoclient log level to debug I can see:
"readPreference":{"mode":"primary"}
showing in the logs for queries and they are going to the primary IP.
Steps to reproduce
Connect to any replicaset using the normal uri string:
mongodb://dbuser:dbpassword@10.0.0.1:27017,10.1.0.1:27017,10.2.0.1:27017/dbname?replicaSet=RS01&w=1&readPreference=nearest&connectTimeoutMS=30000&maxPoolSize=300',
Expected Results
Running mongostat I expect to see queries logged on the nearest db and in the debug logs for the parse server/mongo client I expect to see queries passed to the nearest server. This also happens for secondary or secondaryPreferred.
Actual Outcome
The readPreference is reset to "PRIMARY".
Environment Setup
-
Server
- parse-server version (Be specific! Don't say 'latest'.) : 2.7.2
- Operating System: Ubuntu 16.04
- Hardware: T2 Large
- Localhost or remote server? AWS
-
Database
- MongoDB version: Percona Server for MongoDB shell version: 3.2.18-3.9
- Storage engine: wiredtiget
- Hardware: T2 Large
- Localhost or remote server? AWS
Logs/Trace
I have added some console log statements to parse-server/lib/Adapters/Storage/Mongo/MongoStorageAdapter.js
I can see that the value "nearest" is correctly used in the constructor, however it is getting reset to "PRIMARY" because calls to _parseReadPreference are all having a undefined value for readPreference passed in. As such they hit lines 628-631 which is marked as being added due to testing and it gets reset to "PRIMARY'.
case undefined:
// this is to match existing tests, which were failing as mongodb@3.0 don't report readPreference anymore
readPreference = ReadPreference.PRIMARY;
break;
My knowledge of the source code is not good enough to trace this back further, but it seems that this is a option to support per query read preferences instead of using the global setting from the URI. If I set this to be:
readPreference = ReadPreference.NEAREST;
then things work as expected.
Activity
flovilmart commentedon Jun 13, 2018
Ok, so basically, the readPreference parse forces PRIMARY when none is provided instead of using the one provided at database initialization level. Are you willing to provide a fix for that? It seems reasonable to change it so readPreference is 'undefined' if not provided.
https://github.com/parse-community/parse-server/blob/master/src/Adapters/Storage/Mongo/MongoStorageAdapter.js#L630
rossdraper commentedon Jun 13, 2018
Thanks for the quick response. It looks like this is a result of the change implemented here: #4449
This was implemented to ensure your tests don't break, and not being familiar with your tests I'm not sure what your desired outcome would be(presumably anything other than undefined). I dont mind having a look, but its 1am here. If you are happy I'm not losing my mind and that this is a genuine bug, then I'll look where the appropriate value is and suggest a fix.
flovilmart commentedon Jun 13, 2018
I believe the readPreference should not be passed on a query basis if it is not provided, as it overrides the default driver behavior. I can have a look too :)
rossdraper commentedon Jun 13, 2018
Thanks for looking at this, I may have made a mistake here, but, I've manually put in your change(excluding the spec files) by commenting out the line) and it doesn't resolve my issue. Reads go to the Primary again. If I do the following:
Then it works as I would expect.
flovilmart commentedon Jun 13, 2018
Uhm... interesting, but what bothers me is that we should not touch this prop, the driver should do it’s job and use the provided readPreference unless specified.
I perhaps suspect that passing readPreference: undefined, makes the driver use the primary.
What if your ‘delete’ readPreference if undefined, jnstesd of you ur workaround?
rossdraper commentedon Jun 18, 2018
Apologies for the delay in replying. Sorry, I'm not sure I understand what you want me to do? If you can point me to the section of code that parses and creates the structure for the mongodb URI, I can look deeper as my above solution only works if you add the databaseOptions parameter at the top level. Many thanks. I"m not sure why my URI readPreference at the URI level is not adhered to when using your submitted fix.
flovilmart commentedon Jun 18, 2018
I believe the issue lies in passing undefined. And the driver sets internally as PRIMARY, not the connection parameter.
My suggestion would be to not pass the readPreference if it’s un defined at all. Do you follow?
rossdraper commentedon Jun 18, 2018
Understood. Thanks for clarification. Let me test again on my side and update you.
rossdraper commentedon Jun 18, 2018
If I understand correctly it appears that if you omit the readPreference entirely it is defaulting to PRIMARY. I've tested this by simply commenting out in MongoStorageAdaptor as follows:
with debug logging, I still see all requests going to the PRIMARY despite the database object clearly showing readPreference is nearest:
Db {
domain: null,
_events: { error: [Function], close: [Function] },
_eventsCount: 2,
_maxListeners: undefined,
s:
{ databaseName: 'mydb,
dbCache: {},
children: [],
topology:
ReplSet {
domain: null,
_events: [Object],
_eventsCount: 22,
_maxListeners: undefined,
clientInfo: [Object],
s: [Object] },
options:
{ w: 1,
readPreference: [Object],
promiseLibrary: [Function: Promise] },
logger: Logger { className: 'Db' },
bson: BSON {},
readPreference: ReadPreference { mode: 'nearest', tags: undefined, options: undefined },
bufferMaxEntries: -1,
parentDb: null,
pkFactory: undefined,
nativeParser: undefined,
promiseLibrary: [Function: Promise],
noListener: false,
readConcern: undefined },
serverConfig: [Getter],
bufferMaxEntries: [Getter],
databaseName: [Getter] }
flovilmart commentedon Jun 18, 2018
That would mean that at large the driver option is not respected when initializing it. Which is odd..
Adds test confirming #4831 is properly functional now
flovilmart commentedon Jun 27, 2018
@rossdraper have a look at this particular commit 87a7c96 Everything looks fine now.
Adds test confirming #4831 is properly functional now
Update mongodb to the latest version 🚀 (#4855)
Update mongodb to the latest version 🚀 (#4855)
Update mongodb to the latest version 🚀 (#4855)
Update mongodb to the latest version 🚀 (parse-community#4855)