可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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}});
回答2:
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();
回答3:
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);
});
});
回答4:
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
回答5:
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.
回答6:
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}});
}
});
回答7:
@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
ES6 version (with Promise)
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.
回答8:
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
回答9:
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));
回答10:
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):