diff --git a/lib/storage/mongo-storage.js b/lib/storage/mongo-storage.js index 8c2533873c79..632f1cfa82ee 100644 --- a/lib/storage/mongo-storage.js +++ b/lib/storage/mongo-storage.js @@ -1,18 +1,19 @@ 'use strict'; -var mongodb = require('mongodb'); -var connection = null; -var MongoClient = mongodb.MongoClient; -var mongo = {}; +const MongoClient = require('mongodb').MongoClient; -function init (env, cb, forceNewConnection) { +const mongo = { + client: null, + db: null, +}; - function maybe_connect (cb) { +function init(env, cb, forceNewConnection) { - if (connection != null && !forceNewConnection) { + function maybe_connect(cb) { + + if (mongo.db != null && !forceNewConnection) { console.log('Reusing MongoDB connection handler'); // If there is a valid callback, then return the Mongo-object - mongo.db = connection; if (cb && cb.call) { cb(null, mongo); @@ -23,61 +24,54 @@ function init (env, cb, forceNewConnection) { } console.log('Setting up new connection to MongoDB'); - var timeout = 30 * 1000; - var options = { - reconnectInterval: 10000 - , reconnectTries: 500 - , connectTimeoutMS: timeout - , socketTimeoutMS: timeout - , useNewUrlParser: true + const timeout = 10 * 1000; + const options = { + connectTimeoutMS: timeout, + socketTimeoutMS: timeout, + useNewUrlParser: true, + useUnifiedTopology: true, }; - var connect_with_retry = function(i) { - - MongoClient.connect(env.storageURI, options) - .then(client => { - console.log('Successfully established a connected to MongoDB'); - - var dbName = env.storageURI.split('/').pop().split('?'); - dbName = dbName[0]; // drop Connection Options - mongo.db = client.db(dbName); - connection = mongo.db; - mongo.client = client; - - mongo.db.command({ connectionStatus: 1 }).then( - result => { - const roles = result.authInfo.authenticatedUserRoles; - if (roles.length > 0 && roles[0].role == 'readAnyDatabase') { - console.error('Mongo user is read only'); - cb(new Error('MongoDB connection is in read only mode! Go back to MongoDB configuration and check your database user has read and write access.'), null); - } - - console.log('Mongo user role seems ok:', roles); - - // If there is a valid callback, then invoke the function to perform the callback - if (cb && cb.call) { - cb(null, mongo); - } - } - ); - }) - .catch(err => { - if (err.message && err.message.includes('AuthenticationFailed')) { - console.log('Authentication to Mongo failed'); - cb(new Error('MongoDB authentication failed! Double check the URL has the right username and password in MONGODB_URI.'), null); - return; - } - - if (err.name && err.name === "MongoNetworkError") { - var timeout = (i > 15) ? 60000 : i * 3000; - console.log('Error connecting to MongoDB: %j - retrying in ' + timeout / 1000 + ' sec', err); - setTimeout(connect_with_retry, timeout, i + 1); - if (i == 1) cb(new Error('MongoDB connection failed! Double check the MONGODB_URI setting in Heroku.'), null); - } else { - cb(new Error('MONGODB_URI ' + env.storageURI + ' seems invalid: ' + err.message)); - } - }); - + const connect_with_retry = async function (i) { + + mongo.client = new MongoClient(env.storageURI, options); + try { + await mongo.client.connect(); + + console.log('Successfully established a connected to MongoDB'); + + const dbName = mongo.client.s.options.dbName; + mongo.db = mongo.client.db(dbName); + + const result = await mongo.db.command({ connectionStatus: 1 }); + const roles = result.authInfo.authenticatedUserRoles; + if (roles.length > 0 && roles[0].role == 'readAnyDatabase') { + console.error('Mongo user is read only'); + cb(new Error('MongoDB connection is in read only mode! Go back to MongoDB configuration and check your database user has read and write access.'), null); + } + + console.log('Mongo user role seems ok:', roles); + + // If there is a valid callback, then invoke the function to perform the callback + if (cb && cb.call) { + cb(null, mongo); + } + } catch (err) { + if (err.message && err.message.includes('AuthenticationFailed')) { + console.log('Authentication to Mongo failed'); + cb(new Error('MongoDB authentication failed! Double check the URL has the right username and password in MONGODB_URI.'), null); + return; + } + + if (err.name && err.name === "MongoServerSelectionError") { + const timeout = (i > 15) ? 60000 : i * 3000; + console.log('Error connecting to MongoDB: %j - retrying in ' + timeout / 1000 + ' sec', err); + setTimeout(connect_with_retry, timeout, i + 1); + if (i == 1) cb(new Error('MongoDB connection failed! Double check the MONGODB_URI setting in Heroku.'), null); + } else { + cb(new Error('MONGODB_URI ' + env.storageURI + ' seems invalid: ' + err.message)); + } + } }; return connect_with_retry(1); @@ -85,14 +79,14 @@ function init (env, cb, forceNewConnection) { } } - mongo.collection = function get_collection (name) { - return connection.collection(name); + mongo.collection = function get_collection(name) { + return mongo.db.collection(name); }; - mongo.ensureIndexes = function ensureIndexes (collection, fields) { - fields.forEach(function(field) { + mongo.ensureIndexes = function ensureIndexes(collection, fields) { + fields.forEach(function (field) { console.info('ensuring index for: ' + field); - collection.createIndex(field, { 'background': true }, function(err) { + collection.createIndex(field, { 'background': true }, function (err) { if (err) { console.error('unable to ensureIndex for: ' + field + ' - ' + err); }