Search code examples
node.jsasynchronousjake

Synchronous Jake Node.js task


Can someone help me with closing the database after two models are added to the database? I've tried reading

http://howtonode.org/intro-to-jake

Node.js and Jake - How to call system commands synchronously within a task?

and the github readme at https://github.com/mde/jake

but still can't seem to figure it out. Here's an excerpt from the readme

Cleanup after all tasks run, jake 'complete' event The base 'jake' object is an EventEmitter, and fires a 'complete' event after running all tasks. This is sometimes useful when a task starts a process which keeps the Node event-loop running (e.g., a database connection). If you know you want to stop the running Node process after all tasks have finished, you can set a listener for the 'complete' event, like so:

jake.addListener('complete', function () {
  process.exit();
});

As it is now, it's closing the connection before it even opens it.

// db connect
var db = require('./schema');

desc('Seed MongoDB with initial data');
task('seed', [], function () {

    //******* Populate the database
    var user1 = new db.userModel({ email: '[email protected]', password: 'x', phone: x });
    user1.save(function(err) {
        if(err) {
            console.log(err);
        } else {
            console.log('user: '+user1.email +' saved');
        }
    });
    var user2 = new db.userModel({ email: 'x', password: 'x', phone: x });
    user2.save(function(err) {
        if(err) {
            console.log(err);
        } else {
            console.log('user: '+user2.email +' saved');
        }
    });

    db.mongoose.connection.close();
    console.log('Closed mongodb connection');
});

Edit: I was able to accomplish what I was going for using parallel flow from the parseq module.

par(
  function() {
    fs.readFile("file1", this);
  },
function() {
  fs.readFile("file2", this);
},
function done(err, results) {
  ...
}
);

Edit2: So I REALLY appreciate all the help. I also saw you were the maintainer of parseq :). Thx for that! I'm still struggling with this last bit and my function is hanging and not calling done() when function 5 is complete. I'm sure I'm calling 'this' incorrectly. Any advice?

seq(
    function f1() {
        var user = new db.userModel({ email: 'x'
                        , password: 'x'
                        , phone: x });
        user.save(this);
    }, 
    function f2(err, value) {
        var user = new db.userModel({ email: 'x'
                        , password: 'x'
                        , phone: x });
        user.save(this);
    }, 
    function f3(err, value) {
        var merchant = new db.merchantModel({ name: 'x'
                        , logourl: 'x' });
        merchant.save(this);
    }, 
    function f4(err, value) {
        var merchant = new db.merchantModel({ name: 'x'
                        , logourl: 'x' });
        merchant.save(this);
    }, 
    function f5(err, value) {
        db.merchantModel.findOne({ name: 'x' }, function(err, merchant) {
            var coupon = new db.couponModel({ merchant_id: merchant.id
                            , name: 'x'
                            , imageurl: 'x'
                            , expiration: Date.UTC(2013,3,15) });
                            //, expiration: new Date(2013,3,15) }); //alternate date creation method
            coupon.save(this);
        });
    }, 
    function done(err) {
        if(err) {
            console.log(err);
        } else {
            console.log('successfully seeded db');
        }
        db.mongoose.connection.close();
        console.log('Closed mongodb connection');
    }
);

Solution

  • you need to call db.mongoose.connection.close after both save functions have completed. Easiest would be to nest the save calls (but not the prettiest).

    var user1 = new db.userModel({ email: '[email protected]', password: 'x', phone: x });
    user1.save(function(err) {
        if(err) {
            console.log(err);
        } else {
            console.log('user: '+user1.email +' saved');
        }
        var user2 = new db.userModel({ email: 'x', password: 'x', phone: x });
        user2.save(function(err) {
            if(err) {
                console.log(err);
            } else {
                console.log('user: '+user2.email +' saved');
            }
            db.mongoose.connection.close();
            console.log('Closed mongodb connection');
        });
    });
    

    You should then start looking into a flow control library to make your code simpler.

    same thing using parseq:

    var seq = require("parseq").seq;
    
    seq(
      function f1() {
        var user1 = new db.userModel({ email: '[email protected]', password: 'x', phone: x });
        user1.save(this);
      }, function f2(err, value) {
        var user2 = new db.userModel({ email: 'x', password: 'x', phone: x });
        user2.save(this);
      }, function done(err) {
        // check err here
        console.log('Closed mongodb connection');
      }
    );
    

    to ignore some errors selectively, here's how one function could look like:

    function f1() {
        var self = this;
        var user1 = new db.userModel({ email: '[email protected]', password: 'x', phone: x });
        user1.save(function(err) {
          if (err === SOMETHING_TO_IGNORE) {
            self(null);
          else {
            self(err);
          }
        });
      }