Is this a good way to connect to mongoDB from a nodejs dockerized application? Sometimes mongoDb docker is no ready, so I need to try to connect again to be sure mongoDb docker container is ready and keep executing the following promises.
docker_compose.yaml file already has a dependency defined between applicacion and mongoDB.
Cheers!
private connect() {
return new Promise((resolve, reject) => {
mongoose.connect(`mongodb://${process.env.DB_HOST}/${process.env.DB_NAME}`, {useNewUrlParser: true, useFindAndModify: false}, (err) => {
if (err) {
log.error(err.message);
setTimeout(this.connect, 1000);
} else {
log.info('--> App Connected to MongoDb');
resolve();
}
});
});
}
private init() {
const promises = [
() => this.connect(),
() => this.loadConfig(),
() => this._webHookService.init(),
() => this._cronService.init()
];
return promises.reduce((p, fn) => p.then(fn).catch(error => log.error(error)), Promise.resolve());
}
Related
I am working on converting my Electron project to use Electron v16 which uses contextBridge for the Node built-in modules.
I currently have this, which uses the net module:
import { Socket } from 'net'
async function portConnection (portConfig) {
const client = await new Socket()
client.setKeepAlive(true, 60000)
return new Promise((resolve, reject) => {
client.connect(portConfig.port, portConfig.host)
client.on('connect', () => {
return resolve(client)
})
client.on('timeout', () => {
return reject(new Error('Connection timeout'))
})
client.on('error', (error) => {
return reject(error)
})
})
}
This gives me an error:
TypeError: client.setKeepAlive is not a function
So I added this to the webpack config:
// I know this is not advised, but for simplicity I tried to overwrite the
// 'net' module with one that I preloaded from electron-preload
Object.assign(cfg.externals, {
net: 'window.netPreload'
})
Then I also moved the setKeepAlive function to electron-preload.js:
import { Socket } from 'net'
let client = null
contextBridge.exposeInMainWorld('netPreload', require('net'))
contextBridge.exposeInMainWorld('netApi', {
async createClient () {
client = await new Socket()
return client
},
async keepAlive () {
if (!client) console.error('No client defined')
client.setKeepAlive(true, 60000)
},
async connect (port, host) {
if (!client) console.error('No client defined')
client.connect(port, host)
}
})
Then I call it like this:
async function portConnection (portConfig) {
const client = await window.netApi.createClient()
await window.netApi.setKeepAlive()
return new Promise((resolve, reject) => {
client.connect(portConfig.port, portConfig.host)
client.on('connect', () => {
return resolve(client)
})
client.on('timeout', () => {
return reject(new Error('Connection timeout'))
})
client.on('error', (error) => {
return reject(error)
})
})
}
Now I am getting an error:
TypeError: client.on is not a function
I dont really want to add a contextBridge method for each method in 'net' module. Is there any way to do this?
Also, in this case, how can I 'overwrite' with a polyfill the <net.Server> returned by the command new Socket()?
Im trying to decouple my express server start from the mongodb connection process .
mongodb.connect(process.env.CONNECTIONSTRING, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) {
if (err) {
throw new Error(err)
}
module.exports = client
const server = require("./server")
server.start(opts, t => {
console.log(`server is up 4000`)
})
})
so instead of this single file I would like to have two files one used for mongodb connection , and other for starting the server . when i did this I got error related to mongodb, I think because the server started even before the mongodb conection was established.
any idea on how to solve this
Wrap it in a promise and call it wherever you want
Create a file name db.js it whatever else you want and require in the file that you need it. Then wrap the callback in a promise and export it for usage outside the file. Example above.
function initMongo() {
mongodb.connect(process.env.CONNECTIONSTRING, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) {
return new Promise((resolve, reject) => {
if (err) {
return reject(err);
}
return resolve(client)
})
})
}
module.exports = { initMongo };
Then in your init function, you could call
const server = require("./server");
const mongoDb = require("./db");
async init() {
let client;
try {
client = await mongoDb.initMongo()
} catch(e) {
// could not connect to db
}
server.start(opts, t => {
console.log(`server is up 4000`)
})
}
I am separating the connect function of MongoDB to a separate module, so that the mongoDB connection is reusable. The issue is, I could not get the client/DB variable outside the connect function. It shows undefined.
var MongoClient = require('mongodb').MongoClient;
var _client;
var mongoURL = "mongodb://localhost:27017/";
module.exports = {
connectToMongoServer: (callback) => {
MongoClient.connect(mongoURL,{ useNewUrlParser: true },function(err,client){
_client = client;
return callback(err);
});
},
getClient: () => {
return _client;
}
};
Within the connect function, the _client details contains the information, but if I return it using getClient, it shows undefined.
MongoDB - v3.6.5
Node - v9.9.0
I've made up a snippet which should work the same ad your code, and it works.
So I think the problem is how you are calling your function getClient(); are you sure you are calling it after it get connected?
var _client;
function someAsyncFunc(callback) {
setTimeout(() => callback(false, 'client'), 500);
}
const file = {
connectToMongoServer: (callback) => {
someAsyncFunc(function(err, client) {
_client = client;
return callback(err);
});
},
getClient: () => {
return _client;
}
};
console.log('display one :', file.getClient());
file.connectToMongoServer((err) => {
console.log('display error :', err);
console.log('display two :', file.getClient());
});
I cannot make MongoClient.connect to await for the results before going on.
I am trying to pass db from the server.js, where I connect my mongoclient, to my routes/api.js where I do my post requests. But it does not work, I always get:
TypeError: Cannot read property 'collection' of undefined
Here is my routes/api.js:
var db = require("../server");
router.post('/video_url', async (req, res) => {
const cursor = db.collection('movie').findOne({ link: req.body.videoURL }, function (findErr, result) {
if (findErr) throw findErr;
console.log(cursor)
});
server.js:
var db = async function () {
return await MongoClient.connect(MONGODB_URI, function(err, client) {
try {
if(err) throw err;
db = client.db('sub-project');
// Start the application after the database connection is ready
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
return db;
}
catch(ex) {
console.log(ex)
}
});
}
module.exports = db;
EDIT:
var dbObject = (async function() {
var connection = await new Promise(function(resolve, reject) {
MongoClient.connect(MONGODB_URI, { useNewUrlParser: true }, function(err, client) {
try {
if (err) throw err;
db = client.db('sub-project');
// Start the application after the database connection is ready
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
resolve(db);
} catch (ex) {
console.log(ex)
reject(ex);
}
});
});
return connection;
})();
console.log("TYPEOF DB IN", typeof(dbObject))
console.log("TYPEOF DB.COLLECTION IN", typeof(dbObject.collection))
The both console.log() are undefined... is that normal?
Use this code for your server.js. Your code was not working because your function was not getting called when you are requiring it.
var dbObject;
(function() {
MongoClient.connect(MONGODB_URI, { useNewUrlParser: true }, function(err, client) {
try {
if (err) throw err;
db = client.db('sub-project');
// Start the application after the database connection is ready
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
dbObject = db;
} catch (ex) {
console.log(ex);
}
});
})();
setTimeout(function() {
console.log("TYPEOF DB IN", typeof(dbObject))
console.log("TYPEOF DB.COLLECTION IN", typeof(dbObject.collection))
}, 2000);
module.exports = dbObject;
I have created a mongodb native connection and saved it and then using findOne to query a document.
const Promise = require("bluebird");
const MongoClient = require('mongodb').MongoClient;
let mongoDB = undefined;
const getCollection = (collName) => {
if (mongoDB) {
return Promise.resolve(mongoDB.collection(collName));
} else {
return MongoClient.connect(EXT_CONFS.MONGODB_URL)
.then(db => {
mongoDB = db;
return Promise.resolve(mongoDB.collection(collName));
}).catch(e => {
console.error('Error in MongoDb connection');
});
}
};
const findOne = (collName, filter, options) => {
return getCollection(collName)
.then(collection => {
return collection.findOne(filter, options);
})
.then(doc => {
return Promise.resolve(doc);
}).catch(e => {
console.error(e);
return Promise.reject(e);
});
};
Now this all works fine, but if Mongo ShutsDown / Fails after db client is cached, There is no way to handle error. Error never goes to any catch handler :
console.error('Error in MongoDb connection');
or
console.error(e);
I even tried events :
mongoDB.on('connecting', function () {
console.log('connecting');
});
mongoDB.on('timeout', function (error) {
console.log('timeout!');
});
mongoDB.on('close', function (error) {
console.log('close!');
});
mongoDB.on('error', function (error) {
console.error('Error in MongoDb connection: ' + error);
});
mongoDB.on('connected', function () {
console.log('connected!');
});
mongoDB.on('connection', function () {
console.log('connected!');
});
mongoDB.on('connect', function () {
console.log('connected!');
});
mongoDB.once('open', function () {
console.log('connection open');
});
mongoDB.on('reconnected', function () {
console.log('reconnected');
});
mongoDB.on('disconnected', function () {
console.log('disconnected');
});
but no success still. Using NodeJS 4.5.0, MongoDB-Native driver 2.2.24
You should do something like console.error('Failed to connect to mongodb ',e); you are not outputting the error.
Also some events provide an additional parameter and you are outputting those either. In case of failing to connect to an mongodb server, your application should just notify you it's not the best approach to handle mongodb server start/restart from your application use daemons such as systemd or other process monitoring.
Some events are there to just notify the application that connection was lost or an reconnection is attempted, its up to you to handle what is going to be done when those events are emitted.
You can for example attempt to check mongodb status when an disconnect event is emitted an recreate connection object.
You could wrap the connect statement in a try-catch block.