Akshat Goel
Akshat Goel

Reputation: 786

Flow/pattern for complex calls in node.js

I am building a social community where a user is rewarded if someone upvotes/shares his/her answers. I also send a notification to the user when his/her answer has some interaction.

I have explained the flow though comments in the following code. The function post_event is exposed to the API and the flow begins from there.

var answerController = function(){
    Emitter.call(this);
    var self = this;
    var continueWith = null;

    var push_event = function(event, answerId, likerId, callback){

        // check for data and prepare a bacth of queries
        // has to be done like this coz mongoose doesn't (yet) support nModified, nMatched for update
        var batch = Answer.collection.initializeOrderedBulkOp();
        batch.find(query).upsert().updateOne(update);
        batch.execute(function(err,result) {
            if(err){
                return callback(err);
            }else{
                return callback(null, result.nModified);
            }
        });
    };


    // exposed as an API call for yo/share/view
    // calls push_event
    var post_event = function(req,res, next){

            //check for data in incoming request and pass it forward

            push_event(event,answerId, likerId, function(err, num_updated_docs){
                if(err){
                    return errors.api_error({code: 500, message: err, res: res, next: next});
                }else{
                    if(num_updated_docs){
                        // create the calculateScore_args variable
                        self.emit('calculateScore',calculateScore_args);
                        res.status(200).send({message : 'success'}).end();
                    }else{
                        return errors.api_error({code: 401, message: 'event already exists for user', res: res, next: next});
                    }
                }
            });

    };


    var score = function(args){

        var asyncTasks = [];
        asyncTasks.push(function(cb){
            //update user's score
            // this is a cpu intensive function (does a small matrix multiplication)
        })

        asyncTasks.push(function(cb){
            //update answer's score  (user's score is a function of various answers)
            // another CPU intensive call, calculates confidence interval --->  score
        })

        async.parallel(asyncTasks, function(err, results){
            self.emit('notify', notifyData);
          })

    };

    function notify(args){
        // calls another controller which notifies the user(GCM) and inserts the notification into the DB
        notification.AnswerEvent(args);

    }

    self.on('calculateScore', score);
    self.on('notify',notify);

    return {
        post_event : post_event
    }
};

Question : I would like to know if this is a feasible pattern for a system that would receive around 100-200 req/sec. It would be great if someone can advice me on other patters (like message queue) to follow. Also, what is the best way to debug event emitter code.

Thanks

Upvotes: 0

Views: 177

Answers (1)

snozza
snozza

Reputation: 2253

Moving CPU intensive code out of the web server is the first and foremost way to prevent blocking.

A task queue is a very straightforward way to achieve this. With Ruby, I've used https://github.com/resque/resque with quite a bit of success in the past.

A node port such as https://github.com/taskrabbit/node-resque may be appropriate for your needs. You basically create a job, put it on a queue, and spin up some workers to chew off the required work.

Upvotes: 1

Related Questions