1
\$\begingroup\$

This implementation was derived from the following requirements. I would like to learn that whether the implementation is clean enough, without memory leak and performance hit.

Requirements

  1. Always return either ready to be used DB object, or error if not available.
  2. Reconnect automatically (passive), even in the event of explicit call of db.close() occurred.
  3. Unessential implementation of a express.js compatible middleware to inject the DB object into request object. This may be ignored while reviewing.

Possible issues

  1. Possible memory leak on registering error and close events handler (not sure since my understanding of the once interface is that it would immediately unregister the handler after being invoked).
  2. Possible "race condition" on async calls of the get() function which would cause unexpected creation of connections.

For the "race condition" one, how do I safely and elegantly solve it? Also, if there're already proper implementations available that fits the requirement and doesn't exhibit any of the concerns and known issues, I'd be appreciated to learn as well.

Module implementation

/*
  Mongo helper, exposes access to Mongo DB object as req.mongo, as well as a
  get() method for similar effect. Reconnection is wrapped and handled within.
*/
var MongoClient = require('mongodb').MongoClient;
var logger = require('tp-logger')();

module.exports = function() {
  // arguments to be forwarded to MongoClient.connect()
  var _args = arguments;
  // reused db
  var _db;
  // connected flag
  var _connected = false;
  // DB error/close events handler
  var _onClose = function(err) {
    if (err) {
      if (_db) _db.close();
      logger.error('MongoDB closed on error', err.stack);
    } else {
      logger.log('MongoDB closed');
    }
    _connected = false;
  };

  function _get(callback) {
    // already connected
    if (_connected) return callback(null, _db);
    // reset connection
    MongoClient.connect.apply(MongoClient, _args).then(function(db) {
      _connected = true;
      _db = db;
      _db.once('close', _onClose).once('error', _onClose);
      return callback(null, _db);
    }).catch(function(err) {
      _connected = false;
      return callback(err);
    });
  }

  return {
    // express.js compatible middleware
    middleware: function(req, res, next) {
      _get(function(err, db) {
        if (err) return next(err);
        req.mongo = db;
        return next();
      });
    },
    get: _get
  };
};
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.