How to handle mongoose.connect()
error in catch handler? I want to use application initialization chain but can't do that because mongoose.connect()
does not return rejected promise. It returns rejected promise only if I specify callback, but it's not a perfect solution.
Example:
mongoose.connect('mongodb://127.0.0.2/test') // if error it will throw async error
.then(() => { // if all is ok we will be here
return server.start();
})
.catch(err => { // we will not be here...
console.error('App starting error:', err.stack);
process.exit(1);
});
Workaround:
mongoose.connect('mongodb://127.0.0.2/test', function() { /* dummy function */ })
.then(() => {
return server.start();
})
.catch(err => { // mongoose connection error will be handled here
console.error('App starting error:', err.stack);
process.exit(1);
});
I think mongoose.connect()
throws async error instead of return rejected promise in order to not break backward compatibility. Users expect that application will be finished with error code if something went wrong with mongoose connection establishment. If mongoose.connect()
returns rejected promise application will be finished with 0 code and nothing will be output to console. So it will be good to have some way to say mongoose.connect()
to return promise. Maybe something like exec()
:
mongoose.connect('mongodb://127.0.0.2/test').exec()
.then(() => { // if all is ok we will be here
return server.start();
})
.catch(err => { // if error we will be here
console.error('App starting error:', err.stack);
process.exit(1);
});
mongoose.connect('mongodb://localhost/dbCollection', function(err, db) {
if (err) {
console.log('Unable to connect to the server. Please start the server. Error:', err);
} else {
console.log('Connected to Server successfully!');
}
});
@nasr18 What did you mean? :smiley: I don't want to use callback)
@Jokero sorry dude......... misunderstood your question. :)
Use the callback of mongoose.connect to catch any error during the connection.
You can start you server in the event open.
mongoose.connection.once('open', function() {
logger.info('MongoDB event open');
logger.debug('MongoDB connected [%s]', url);
mongoose.connection.on('connected', function() {
logger.info('MongoDB event connected');
});
mongoose.connection.on('disconnected', function() {
logger.warn('MongoDB event disconnected');
});
mongoose.connection.on('reconnected', function() {
logger.info('MongoDB event reconnected');
});
mongoose.connection.on('error', function(err) {
logger.error('MongoDB event error: ' + err);
});
// return resolve();
return server.start();
});
return mongoose.connect(url, options, function(err) {
if (err) {
logger.error('MongoDB connection error: ' + err);
// return reject(err);
process.exit(1);
}
});
@mathieug I know, I can use callback for error handling but issue is about promises :smiley:
Don't use the promise from mongoose.connect, start your server when the connection is open for the first time (.once('open'))
Why? No difference at all. When connection is opened, mongoose.connect
callback will be called as well as returned promise will be fulfilled and open
event will be emitted. So you can use what you want
Yes but as you said, mongoose.connect needs a callback in case of error.
That's why I created this issue :smiley:
I have the same issue.
I'd like to be able to use mongoose.connect(...).catch(failCallback)
but when an error occurs upon initial connection attempt failCallback
does not execute. There's something wrong with the MongooseThenable
pseudo-promise that mongoose.connect
returns. Moreover I have configured mongoose.Promise = require('bluebird')
and I really expect such async calls to return a _real_ promise, a Bluebird one in my case.
The problem with my failCallback
not executing, however, happens only initially, i.e.:
// First kill mongod instance so that Mongoose cannot connect and start the app
mongoose.connect(uri, options).catch(failCallback); // failCallback does _not_ get called
// Then stop the app, start mongod instance so that Mongoose can connect, start the app
mongoose.connect(uri, options).then(successCallback); // successCallback gets called
// Then kill mongod instance so that Mongoose disconnects (while the app is running)
mongoose.connection.on('disconnected', function () {
setTimeout(function () {
mongoose.connect(uri, options).catch(reconnectFailCallback); // now reconnectFailCallback _does_ get called
}, randomDelayOfAboutASecond);
});
But indeed it works like that (which is nonsensical):
// First kill mongod instance so that Mongoose cannot connect and start the app
var dummyNoopCallback = function () {};
mongoose.connect(uri, options, dummyNoopCallback).catch(failCallback); // failCallback _does_ get called
Why is that?
Re: returning a real promise, it's that way for backwards compatibility. Unfortunately people rely on .connect()
chaining behavior for some reason (#3847, #3790, etc) so we're keeping it this way for now :) Added a fix so .catch()
can catch initial connection issues.
It works! But will these changes break something for those who expect that application process will be finished when connection error is happened and there are no callback and promise handlers?
Example:
const mongoose = require('mongoose');
mongoose.Promise = Promise;
mongoose.connect('mongodb://127.0.0.2/test'); // no callback and promise handlers
Before these changes
/home/dmitry/example/node_modules/mongodb/lib/server.js:242
process.nextTick(function() { throw err; })
^
Error: connect ECONNREFUSED 127.0.0.2:27017
at Object.exports._errnoException (util.js:870:11)
at exports._exceptionWithHostPort (util.js:893:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1057:14)
With these changes process is finished with 0 code
Thanks for the suggestion, will investigate.
Cool! Thanks :+1:
+1
Would love to be able to return the result of .connect() as a full fledged Promise in the initialization chaining.
@CodeJjang does this not work already? This functionality has already been released
mongoose.connect('mongodb://127.0.0.2/test', function() { /* dummy function */ })
.then(() => {
return server.start();
})
.catch(err => { // mongoose connection error will be handled here
console.error('App starting error:', err.stack);
process.exit(1);
});
This is not working for me :(
It show
(node:22564) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [127.0.0.1:27017] on first connect
Hmm try getting rid of the callback in mongoose.connect()
I just got:
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1):
MongoError: failed to connect to server [localhost:17551] on first connect
not using promises on mongoose 4.7.6 (latest right now), any way to avoid that Warning?
I'm using it with ExpressJS and if I use catch, it screws my logic and behaves weird as express-session
is creating a MongoStore too... just messy.
Code sample please
I have the same issue as @matheo. Just opened this ticket:
Just to confirm for anyone coming later, this works as expected:
mongoose.connect('http://127.0.0.1:27017/test')
.then(() => {
server.start();
})
.catch((err) => {
console.log('Error on start: ' + err.stack);
process.exit(1);
});
Just to confirm for anyone coming later, this works as expected:
mongoose.connect('http://127.0.0.1:27017/test') .then(() => { server.start(); }) .catch((err) => { console.log('Error on start: ' + err.stack); process.exit(1); });
I'm using this approach too! But when I stop mongodb then run this code, it's not working.
// mongoose version 5.4.14
mongoose
.connect(databaseUri, {
promiseLibrary: bluebird,
useNewUrlParser: true,
useFindAndModify: false,
useCreateIndex: true,
// Automatically try to reconnect when it loses connection to MongoDB
autoReconnect: true,
// Never stop trying to reconnect
reconnectTries: Number.MAX_VALUE,
// Reconnect every 500ms
reconnectInterval: 500,
// Maintain up to 10 socket connections. If not connected,
// return errors immediately rather than waiting for reconnect
poolSize: 10,
// Give up initial connection after 10 seconds
connectTimeoutMS: 10000,
})
.catch((err) => {
console.log(err);
process.exit(1);
});
@nvtuan305 what do you mean by 'not working'? Is there some error messages?
@vkarpov15 I mean no error will be printed
Procedure:
catch
block will not been reached. // Never reach to here
console.log(err);
process.exit(1);
@nvtuan305 if initial connection times out, mongoose will report an error after connectTimeoutMS
. Is that not the case for you? If so, what version of MongoDB and mongoose?
@vkarpov15
mongoose will report an error after
connectTimeoutMS
In my case, mongoose doesn't report error after connectTimeoutMS
at catch
block. I'm using Mongodb 3.6.5 and mongoose 5.4.14
> mongod --version
db version v3.6.5
git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
OpenSSL version: OpenSSL 1.0.2p 14 Aug 2018
allocator: system
modules: none
build environment:
distarch: x86_64
target_arch: x86_64
@nvtuan305 just to confirm, are you connecting to a standalone mongodb instance or a replica set?
@vkarpov15 I'm using standalone instance.
@nvtuan305 what operating system? Also, why do you expect Mongoose to fail to connect to the standalone - is the mongod
instance down, is there no network connection, something else?
Below script works as expected:
const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);
run().then(() => console.log('done')).catch(error => console.error(error.stack));
async function run() {
console.log(mongoose.version);
const start = Date.now();
const opts = { useNewUrlParser: true, connectTimeoutMS: 1000 };
await mongoose.connect('mongodb://doesntexist.com:27017/test', opts).
catch(error => { console.log(`Caught "${error.message}" after ${Date.now() - start}`); });
}
Output
$ node gh-4135.js
5.4.14
Caught "failed to connect to server [doesntexist.com:27017] on first connect [MongoNetworkError: connection 0 to doesntexist.com:27017 timed out]" after 1024
done
$ ^C
Hey, it seems basic but please double check theses instructions
I solve it doing that
Most helpful comment
Just to confirm for anyone coming later, this works as expected: