13

I am looking for help with a design pattern for creating a database connection in my node.js application.

It seems obvious to do:

module1:

var db;
exports.get_db = function(callback) {

  if (db == null) {
    dblibrary.create(connection_params, function(error, conn) {
      if (error == null) {
        db = conn;
        callback(null, db);
      }
    });
  } else {
    callback(null, db);
  }
};

module2:

exports.do_something = function () {
  module1.get_db(function (err, conn) {
    if (err == null) {
      // continue using query
    }
  });
};

It seems painful to have to penalize every single person who wants to get the db connection with the requirement of using a callback.

I could do this:

module1:

var db;

dblibrary.create_connection(connection_params, function (err, conn) {

  if (err != null) {
     console.log("can't create connection");
     console.log(err);
     process.exit();
  } else {
     db = conn;
  }
});

exports.get_db = function() {
  return db;
};

This makes it so that getting the db connection is simple and fast, but means we have to "wait" at node startup time for the connection to be established.

Which is the better design? Is there a better way of doing things?

MarcWan
  • 2,943
  • 3
  • 28
  • 41

3 Answers3

8

mydb.js module:

var db
exports.db = function() {
    if (db === null) {
        db = dblibrary.createClient()
    }
    return db
}

Other modules:

var db = require('mydb').db()
...
db.query(...)

This creates the DB client instance once at startup. I like this solution because the creation code is encapsulated in a separate module and the other modules can get access to the client with one require() statement.

alienhard
  • 14,376
  • 9
  • 37
  • 28
  • 4
    What happens if dblibrary only has async db creation? There's theoretically a small window of time where mydb.js hasn't finished creating, but the main app might have started executing, no? – MarcWan Jun 08 '11 at 08:21
  • @MarcWan Yes, this doesn't work for async client creation (actually this wouldn't work at all, not just theoretically). I'm using node_redis, which is synchronous. But then, this code is only run once at startup. – alienhard Jun 08 '11 at 08:46
  • 2
    Are you ever concerned that your app shares only a single DB connection? If that connection was tied up in a long running query, wouldn't the rest of your app suffer? – Anthony Webb Mar 16 '13 at 03:37
  • actually when you define a variable with `var` without assigning value, you will get a `undefined` but not a `null`, so in this code you will always get `undefined` – alphakevin May 28 '16 at 13:13
  • A rogue click made me downvote this which I can't remove :/ – RichieAHB Nov 16 '16 at 15:08
4

Best answer I've seen for this is:

in start.js:

    function init_done() {

      app.listen(8080);

    }


init_databases(init_done);

in databases.js:

init_databases(init_done_cb) {

  db.create_async(/* connect data */ , function (err, res) {

    if (err == null) init_done_cb();

  });
}

This way you can do the async startup of the database server without that awkward / dangerous waiting period.

MarcWan
  • 2,943
  • 3
  • 28
  • 41
  • and when/how would you disconnect? – Philipp Kyeck Jul 12 '11 at 16:19
  • Doesn't handle the case when you have command line tasks that also use the model and require a db connection. Connection should be created when its first required, and kept until server is shut down. – deepwell Mar 06 '12 at 18:30
  • I dnt knw whts the advantage of async db, @marcWan you have to make connection var global then only other modules can use easily (no more requires) – Ganesh Kumar Mar 13 '12 at 12:04
0

I wrote connect-once just for solving this kind of problems. There are two main goals, that are achived by this module:

  1. Connection should be initialized before request arrives
  2. Connection should be initialized once, even there are multiple requests coming in at the same time

You can look at express-mongo-db and express-mongoose-db as examples of usage.

floatdrop
  • 615
  • 5
  • 13
  • I don't understand how this helps. The example code is still has a callback. – Ian Warburton Sep 06 '14 at 19:38
  • @ian-warburton Trick is to place incoming client into waiting and create connection once. If clients keep coming and connection already requested - then do nothing. Callback is not a problem here. – floatdrop Sep 08 '14 at 05:23