Reputation: 2214
I want my nodejs app to not continue unless it connects to mongodb.
I tried:
//Mongo
async function mongoConnect(mongoDB) {
var mongoConnectionSuccessful = false;
LOG("Connecting to mongodb at " + mongoDB + "...");
while (!mongoConnectionSuccessful) {
try {
await mongoose.connect(mongoDB, { useNewUrlParser: true, useUnifiedTopology: true });
LOG("connected!");
mongoConnectionSuccessful = true;
mongoose.connection.on('error', ()=>LOG('MongoDB connection error:'));
return;
} catch (error) {
LOG(error);
}
await utils.sleep(500);
}
}
mongoConnect(config.mongoUrl);
but in order to use await
in mongoose.connect
, I must make mongConnect
async
, but I then cannot call it in a blocking way from the code because in order to call like this, I must call with await
, but await is only permitted inside async functions.
Upvotes: 2
Views: 4366
Reputation: 113984
I must call with await, but await is only permitted inside async functions
That's correct. So do just that:
async function main () {
await mongoConnect(config.mongoUrl);
// rest of your code...
}
main();
For example if this is an Express server do something like:
const express = require('express');
const app = express();
async function main () {
await mongoConnect(config.montoUrl);
const routes = require('./my-routes');
app.use(routes);
app.listen(config.port);
}
main();
You don't need to await the main()
function (indeed normally you cannot because it is not in a function marked with async
) because there is no other javascript code after it. It is at the end of the file.
If you want to run some code after your program ends or catch any uncaught async errors you can all main with a .then()
and .catch()
:
main()
.then(() => console.log('done'))
.catch((err) => console.error(err));
Upvotes: 4
Reputation: 126
I assume that for some reason you have incoming events meanwhile you are attempting to connect to mongo. My approach would be preventing any incoming events (such as starting the server and setting listeners) before connection to mongo. If it's not possible, one way to do it is to use a self-invoking function.
//Mongo
async function mongoConnect(mongoDB) {
var mongoConnectionSuccessful = false;
LOG("Connecting to mongodb at " + mongoDB + "...");
while (!mongoConnectionSuccessful) {
try {
await mongoose.connect(mongoDB, { useNewUrlParser: true, useUnifiedTopology: true });
LOG("connected!");
mongoConnectionSuccessful = true;
mongoose.connection.on('error', ()=>LOG('MongoDB connection error:'));
return;
} catch (error) {
LOG(error);
}
await utils.sleep(500);
}
}
(async function() {
// do stuff
await mongoConnect(config.mongoUrl);
// do other stuff
})();
Upvotes: 0
Reputation: 46
I found the solution in this article
I beleive what you need is to promise your call of mongoConnect(config.mongoUrl),
than await promises until it is called back.
async function getConcurrently() {
let promises = [];
promises.push(mongoConnect(config.mongoUrl))
// promises.push(getUsers());
// promises.push(getCategories());
// promises.push(getProducts());
let mongo = await Promise.all(promises);
//let [users, categories, products] = await Promise.all(promises);
}
Please Note this warning in the article:
As the first example, first we create an array of Promises (each one of the get functions are a Promise). Then, we execute all of them concurrently and simultaneously, awaiting for all of them to finish (await Promise.all). Finally, we assign the results to the respective variables users, categories and products. Despite the fact that it works, it’s important to say that using Promises.all() for everything is a bad idea.
Upvotes: 0
Reputation: 1922
You want to attempt reconnect if mongoose
fails to connect. Here is an example logic without helper lib.Props to the guy who posted this solution in a github issue for mongoose
. Here
function createConnection (dbURL, options) {
var db = mongoose.createConnection(dbURL, options);
db.on('error', function (err) {
// If first connect fails because mongod is down, try again later.
// This is only needed for first connect, not for runtime reconnects.
// See: https://github.com/Automattic/mongoose/issues/5169
if (err.message && err.message.match(/failed to connect to server .* on first connect/)) {
console.log(new Date(), String(err));
// Wait for a bit, then try to connect again
setTimeout(function () {
console.log("Retrying first connect...");
db.openUri(dbURL).catch(() => {});
// Why the empty catch?
// Well, errors thrown by db.open() will also be passed to .on('error'),
// so we can handle them there, no need to log anything in the catch here.
// But we still need this empty catch to avoid unhandled rejections.
}, 20 * 1000);
} else {
// Some other error occurred. Log it.
console.error(new Date(), String(err));
}
});
db.once('open', function () {
console.log("Connection to db established.");
});
return db;
}
// Use it like
var db = createConnection('mongodb://...', options);
and with a lib promise-retry
const promiseRetry = require('promise-retry')
const options = {
useNewUrlParser: true,
reconnectTries: 60,
reconnectInterval: 1000,
poolSize: 10,
bufferMaxEntries: 0 // If not connected, return errors immediately rather than waiting for reconnect
}
const promiseRetryOptions = {
retries: options.reconnectTries,
factor: 2,
minTimeout: options.reconnectInterval,
maxTimeout: 5000
}
const connect = () => {
return promiseRetry((retry, number) => {
logger.info(`MongoClient connecting to ${url} - retry number: ${number}`)
return MongoClient.connect(url, options).catch(retry)
}, promiseRetryOptions)
}
module.exports = { connect }
Upvotes: 0