The problem is Mongoose loses its connection in the following scenario:
- Node App is started, all seems fine (DB accessible, etc.)
- Mongo server process (version 2.6.10) running locally is stopped, then started after 15 seconds, all seems fine (DB accessible, etc.)
- Mongo process is stopped.
- a request to Express is made, trying to go to DB (using Mongoose) - inaccessible as expected.
- Mongo process is started.
- The same request is made, DB is inaccessible even though Mongo is up.
If I restart the Node JS app, all works fine.
Why is a failing query (using Mongoose version 4.4.5) to Mongo prevents the connection from being restored when the DB process is up again?
Should we implement a retry mechanism to try and restore the connection until DB becomes accessible?
I've tried the configuration mentioned here but it didn't work.
Any help would be appreciated.
Bellow is a sample code of our connection helper:
'use strict';
const _ = require('lodash');
const mongoose = require('mongoose');
const config = require('../config');
const logger = require('../logger');
const _instance = Symbol('instance');
const _enforcer = Symbol('enforcer');
const _members = Symbol('members');
/**
* Singleton implementation of ConnectionHelper module
* This module is responsible to reusing common db connections in the application
* @type {ConnectionsHelper}
*/
module.exports = class ConnectionsHelper {
constructor(enforcer) {
if (enforcer !== _enforcer) {
throw new Error('invalid singleton instantiation');
}
initConnectionFromConfig.call(this);
}
/**
* The single instance
* @returns {*}
*/
static get instance() {
if (!this[_instance]) {
this[_instance] = new ConnectionsHelper(_enforcer);
}
return this[_instance];
}
/**
* method retrieves connection by its name
* @param connectionKey
* @returns {*}
*/
getConnection(connectionKey) {
return this[_members][connectionKey];
}
/**
* method disconnects all underlying connections
* @returns {void|MongooseThenable}
*/
closeConnections() {
return mongoose.disconnect();
}
};
function initConnectionFromConfig() {
this[_members] = {};
const dbsConnections = config.get('dbsConnections');
_.forEach(dbsConnections, (connection, connectionName) => {
const protocol = connection.protocol;
const repSetPath = connection.mongoPath.join(',');
const options = connection.options;
options.server = {auto_reconnect: true, socketOptions: {keepAlive: 1, connectTimeoutMS: 30000 }};
options.replset = {socketOptions: {keepAlive: 1, connectTimeoutMS: 30000 }};
this[_members][connectionName] = mongoose.createConnection(protocol + repSetPath, options);
addConnectionEvents.call(this, connectionName);
});
}
function initConnectionIfNeeded() {
this[_members] = {};
const dbsConnections = config.get('dbsConnections');
_.forEach(dbsConnections, (connection, connectionName) => {
const protocol = connection.protocol;
const repSetPath = connection.mongoPath.join(',');
const options = connection.options;
//options.server = {auto_reconnect: true, socketOptions: {keepAlive: 1, connectTimeoutMS: 30000 }};
//options.replset = {socketOptions: {keepAlive: 1, connectTimeoutMS: 30000 }};
this[_members][connectionName] = mongoose.createConnection(protocol + repSetPath, options);
addConnectionEvents.call(this, connectionName);
});
}
function addConnectionEvents(connectionName) {
const connection = this[_members][connectionName];
connection.on('connected', () => {
logger.debug(`Mongoose connection open`);
});
connection.on('error', (err) => {
logger.debug(`Mongoose connection error: ${err}`);
});
connection.on('exception', (err) => {
logger.debug(`Mongoose connection exception: ${err}`);
});
connection.on('disconnected', () => {
logger.debug(`Mongoose connection disconnected`);
});
connection.on('reconnected', () => {
logger.debug(`Mongoose connection reconnected`);
});
connection.on('open', () => {
logger.debug(`Mongoose connection is open`);
});
// If the Node process ends, close the Mongoose connection
process.on('SIGINT', () => {
connection.close(() => {
logger.debug(`Mongoose default connection disconnected through app termination`);
process.exit(0);
});
});
}