Reputation: 41440
I'm trying to set up the MongoDB auto reconnection feature via Mongoose. Every way that I have tried to pass the option has had no effect, or at least the reconnected
event isn't being emitted.
What I've tried:
mongoose.createConnection("mongodb://localhost:27017/test", { auto_reconnect: true });
mongoose.createConnection("mongodb://localhost:27017/test", { autoReconnect: true });
mongoose.createConnection("mongodb://localhost:27017/test", { server: { auto_reconnect: true } });
mongoose.createConnection("mongodb://localhost:27017/test", { server: { autoReconnect: true } });
If one of these is correct, the reconnected
event should be triggered and a message should be logged in the console, however this never happens.
If there is a delay before the reconnection, does anyone know how to configure it?
Thanks in advance
For anyone looking into this, take a look at this and this issue in mongoose repository.
Upvotes: 33
Views: 55512
Reputation: 2822
2023 Update:
Unified Topology is now the standard for the latest mongodb drivers. Connections are treated differently. You can listen for disconnect events using mongoose, but it's not necessary for reconnecting.
To spy on the reconnect attempts you can use the mongoose.connection.client (MongoDB v3 or v4 Client) object:
client.on('serverHeartbeatFailed', (e) => {})
This will show you the reconnect attempts ongoing. Defaults to every 10s.
You can still use the mongoose disconnected
or error
events to add your own custom reporting.
Upvotes: 0
Reputation: 3580
To have multiple retries without request blocking while retrying I had to set bufferMaxEntries: 0
:
const dbUri = 'mongodb://localhost/some_db';
const dbOptions = {
useMongoClient: true,
autoReconnect: true,
reconnectTries: Number.MAX_VALUE,
bufferMaxEntries: 0
};
mongoose.connect(dbUri, dbOptions).catch(err => process.exit(1));
Upvotes: 2
Reputation: 6213
Based on @zangw answer, I've finished with this database init function for my app
const mongoose = require('mongoose')
const RETRY_TIMEOUT = 3000
module.exports = function initDB () {
mongoose.Promise = global.Promise
const options = {
autoReconnect: true,
useMongoClient: true,
keepAlive: 30000,
reconnectInterval: RETRY_TIMEOUT,
reconnectTries: 10000
}
let isConnectedBefore = false
const connect = function () {
return mongoose.connect(process.env.MONGODB_URL, options)
.catch(err => console.error('Mongoose connect(...) failed with err: ', err))
}
connect()
mongoose.connection.on('error', function () {
console.error('Could not connect to MongoDB')
})
mongoose.connection.on('disconnected', function () {
console.error('Lost MongoDB connection...')
if (!isConnectedBefore) {
setTimeout(() => connect(), RETRY_TIMEOUT)
}
})
mongoose.connection.on('connected', function () {
isConnectedBefore = true
console.info('Connection established to MongoDB')
})
mongoose.connection.on('reconnected', function () {
console.info('Reconnected to MongoDB')
})
// Close the Mongoose connection, when receiving SIGINT
process.on('SIGINT', function () {
mongoose.connection.close(function () {
console.warn('Force to close the MongoDB connection after SIGINT')
process.exit(0)
})
})
}
There is a few differences: I've added some options to prevent connection closing issue - no reconnect after 30 auto retries, just MongoError: Topology was destroyed for any operation and no reconnect; also I've added .catch after connect to prevent unhandled promise rejection):
Upvotes: 2
Reputation: 10498
After reading the docs, I'm pretty sure you have the options wrong. The connection options string should look like:
mongoose.connect("mongodb://localhost:27017/db", {
socketOptions: {
// This option is on by default, but why not set it explicitly
autoReconnect: true
},
// This options is 1 second by default, its possible the ha
// takes longer than 30 seconds to recover.
reconnectInterval: 5000,
// This options is 30 by default, why not make it 60
reconnectTries: 60
})
Check this page out: http://mongoosejs.com/docs/api.html
Upvotes: 1
Reputation: 32767
@Clive's answer was excellent. Nonetheless, due to using mongoose
with Promise
I was getting the following warning after every failed attempt:
(node:18123) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [localhost:27017] on first connect
I also added a small timeout between reconnects in this version (completely optional), to prevent your screen (or your logger) being flooded of repeated messages.
import mongoose from 'mongoose';
mongoose.Promise = Promise; // Set mongoose to use ES6 Promises.
const dbURI = 'mongodb://127.0.0.1:27017/myDb';
const reconnectTimeout = 5000; // ms.
function connect() {
mongoose.connect(dbURI, { auto_reconnect: true })
.catch(() => {}); // Catch the warning, no further treatment is required
// because the Connection events are already doing this
// for us.
}
const db = mongoose.connection;
db.on('connecting', () => {
console.info('Connecting to MongoDB...');
});
db.on('error', (error) => {
console.error(`MongoDB connection error: ${error}`);
mongoose.disconnect();
});
db.on('connected', () => {
console.info('Connected to MongoDB!');
});
db.once('open', () => {
console.info('MongoDB connection opened!');
});
db.on('reconnected', () => {
console.info('MongoDB reconnected!');
});
db.on('disconnected', () => {
console.error(`MongoDB disconnected! Reconnecting in ${reconnectTimeout / 1000}s...`);
setTimeout(() => connect(), reconnectTimeout);
});
connect();
Further information on Connection events.
Upvotes: 8
Reputation: 3499
Just for the sake of posterity, as most of these answers are old, you should not need to deal with this issue any more, as it is now baked into the nodejs mongodb driver. To quote kdmon:
...reconnecting is now baked into mongoose and enabled by default. But it might be useful to know that Mongoose by default will only try reconnecting for 30s and then give up. Set the server.reconnectTries option to increase the number of times mongoose will try to reconnect. For example, you can tell mongoose to never stop trying to reconnect like this:
mongoose.connect(uri, { server: { reconnectTries: Number.MAX_VALUE } });
See connection docs and server options defaults for details
Upvotes: 12
Reputation: 24319
Plucked from http://bites.goodeggs.com/posts/reconnecting-to-mongodb-when-mongoose-connect-fails-at-startup/
This worked for me:
var mongoose = require('mongoose')
var mongoUrl = "mongodb://localhost:27017/test"
var connectWithRetry = function() {
return mongoose.connect(mongoUrl, function(err) {
if (err) {
console.error('Failed to connect to mongo on startup - retrying in 5 sec', err);
setTimeout(connectWithRetry, 5000);
}
});
};
connectWithRetry();
Upvotes: 21
Reputation: 48406
Recently, I investigate the auto-reconnect with MongoDB
var Mongoose
. There is one issue here, when invoking mongoose.connect
within disconnected
event handler, it will trigger infinite loop. Why the SIGINT signal is blocked when mongoose auto reconnect.
One work around solution could be that the mongoose.connect()
only be called when there is no connection with MongoDB
before. The auto_reconnect
flag could make mongoose reconnect with MongoDB
automatically. Here are code snippets.
var mongoose = require('mongoose');
var isConnectedBefore = false;
var connect = function() {
mongoose.connect('mongodb://localhost/' + + 'test_dev', {server: { auto_reconnect: true }});
};
connect();
mongoose.connection.on('error', function() {
console.log('Could not connect to MongoDB');
});
mongoose.connection.on('disconnected', function(){
console.log('Lost MongoDB connection...');
if (!isConnectedBefore)
connect();
});
mongoose.connection.on('connected', function() {
isConnectedBefore = true;
console.log('Connection established to MongoDB');
});
mongoose.connection.on('reconnected', function() {
console.log('Reconnected to MongoDB');
});
// Close the Mongoose connection, when receiving SIGINT
process.on('SIGINT', function() {
mongoose.connection.close(function () {
console.log('Force to close the MongoDB conection');
process.exit(0);
});
});
Upvotes: 14
Reputation: 3868
Here is an improvement to Clive's answer that sets a minimum of 5 seconds between connection attempts.
var db = mongoose.connection;
var lastReconnectAttempt; //saves the timestamp of the last reconnect attempt
db.on('error', function(error) {
console.error('Error in MongoDb connection: ' + error);
mongoose.disconnect();
});
db.on('disconnected', function() {
console.log('MongoDB disconnected!');
var now = new Date().getTime();
// check if the last reconnection attempt was too early
if (lastReconnectAttempt && now-lastReconnectAttempt<5000) {
// if it does, delay the next attempt
var delay = 5000-(now-lastReconnectAttempt);
console.log('reconnecting to MongoDB in ' + delay + "mills");
setTimeout(function() {
console.log('reconnecting to MongoDB');
lastReconnectAttempt=new Date().getTime();
mongoose.connect(dbURI, {server:{auto_reconnect:true}});
},delay);
}
else {
console.log('reconnecting to MongoDB');
lastReconnectAttempt=now;
mongoose.connect(dbURI, {server:{auto_reconnect:true}});
}
});
Upvotes: 4
Reputation: 1980
Make sure mongoose is also the only way you're connecting to Mongo. In my case, I am using connect-mongo to store sessions in Express, but it does not have auto_reconnect set to true by default, as of v0.4.0.
Upvotes: 3
Reputation: 1746
I had the same question as you, and robertklep's solution didn't work for me either. I found when MongoDB service is stopped, an error event is triggered, but the connection.readyState is still 1 (connected). That may be why it didn't auto reconnect.
This is what I have now:
var db = mongoose.connection;
db.on('connecting', function() {
console.log('connecting to MongoDB...');
});
db.on('error', function(error) {
console.error('Error in MongoDb connection: ' + error);
mongoose.disconnect();
});
db.on('connected', function() {
console.log('MongoDB connected!');
});
db.once('open', function() {
console.log('MongoDB connection opened!');
});
db.on('reconnected', function () {
console.log('MongoDB reconnected!');
});
db.on('disconnected', function() {
console.log('MongoDB disconnected!');
mongoose.connect(dbURI, {server:{auto_reconnect:true}});
});
mongoose.connect(dbURI, {server:{auto_reconnect:true}});
Upvotes: 63