Multiple processes in nodejs and sharing ports

 Development, node.js  Comments Off on Multiple processes in nodejs and sharing ports
Mar 172012
 

Recently I have been doing alot of work with node.js. As part of that work, we used multiple processes spawned by the node main node process. I wanted to just write down and share some of my experiences.

Starting new processes in node is easy
Nodejs docs

Using the child_process module you have several options for creating child processes. These include spawn,
fork and exec.

fork :
duplicates your shell in a sub shell. So if node is running you can run new node code in this new process.

exec :
Normally executes in the current shell replacing the process space. in nodejs it runs the command in a sub shell. To run the command in the current process space you should use execFile

spawn :
duplicates and then execs. So is like calling fork (create new duplicate process) and then execFile (the command you want to run in that environment).

Examples:

   var child = require('child_process');

   var forked = child.fork("./mynewscript.js");

if you were to open up your terminal now and run a ps -ef | grep node, you should see two processes running (assuming the code doesn’t run and immediately exit).
Another useful feature, is that the child and parent process can send messages to one another. Taking the above example you can add.

  forked.on('message', function(msg){
     console.log("parent received message" + msg);
  });
  // send message to child
  forked.send({ hello: 'world' });
  

  //in mynewscript.js
  
  process.on('message', function(m) {
    console.log('CHILD got message:', m);
  });

  process.send({ foo: 'bar' });

Starting new processes that listens on a shared port is easy

Cluster info nodejs
Node.js has a cluster module which is made for sharing ports with multiple processes. “The cluster module allows you to easily create a network of processes that all share server ports.”

A quick example:

 var cluster = require('cluster');

 var server = require('http').createServer(function (req,res){
     res.writeHead(200);
     res.end("hello world");
 });
 var workers = [];
 if(cluster.isMaster){
    for(var i=0; i < 2; i++){
       var worker = cluster.fork();
       workers.push(worker);
    }
   
 }else{
    //forked process space also have server
   server.listen(3001); 
 }

 //restart on death of any sub process
 cluster.on('death', function (worker){
      for(var i=0; i < workers.length){
            var aworker = workers[i];
            if(worker.pid === aworker.pid) workers.splice(i);
      }
     var regen = cluster.fork();
     wokers.push(regen); 
  });

Points to bear in mind

With the clustering if you kill the parent process the child processes will not die and so will continue to serve. If you want to stop all child processes when you stop the parent process do something like:

  process.on('SIGTERM',function(){
     for(var i=0; i < workers.length; i++){
        workers[i].kill('SIGTERM');
    }
    process.exit(1);
 });

Also something to note is that from my testing, if you put the http server on the main process and also on the worker processes, the main process will always answer the request and the child processes will receive none of the requests.

Running Multiple Apps on Same port Nodejs

 Development, general, node.js  Comments Off on Running Multiple Apps on Same port Nodejs
Jan 072012
 

This is actually surprisingly simple due to great work done by nodejitsu and also by the connect team. And I have largely copied the content from the links at the bottom of the page:

So with http proxy you can use it as follows:


npm install http-proxy

-- app.js ---

var http = require('http'),
httpProxy = require('http-proxy');
//
// Create your proxy server
//
var options = {
hostnameOnly: true,
router: {
'foo.com': '127.0.0.1:8001',
'bar.com': '127.0.0.1:8002'
}
}
httpProxy.createServer(options).listen(80);

in terminal run
nohup nodemon app.js & //will keep it running

-- foo.js --

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied 8001!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(8001);

in terminal run nodemon foo.js
-- bar.js --

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied 8001!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(8002);

in terminal run nodemon bar.js

finally edit your /private/etc/hosts file and add:

127.0.0.1 foo.com
127.0.0.1 bar.com

browse to bar.com and foo.com to see that both apps are running.

more info here
nodejitsu http proxy

The vhosts from connect is also really nice:
you can see a really good example of this in action here:

vhosts example

Run nodejs app on centos 5 vps

 node.js, Uncategorized  Comments Off on Run nodejs app on centos 5 vps
Dec 062011
 

So I have been doing quite a lot of experimenting with nodejs. Really enjoying it at the moment.
I started by creating a simple website using the express web framework and mongodb. I ran this app on the cloudfoundry service.
After doing this I decided to do something a little more challenging and interesting.
I’m going to be building a html5 and javascript multiplayer game and using nodejs on the server side for the tcp server.

I have already started on the code base locally, but wanted to run it on my vps so Today I got nodejs installed and connected to my nodejs tcp server.

For those interested in installing nodejs on centos 5 here is what I did:

First I installed the centos development tools package using yum:


yum groupinstall 'Development Tools' you may already have this.

Next I got nodejs from nodejs.org/dist/ and used wget to pull it down; you could also clone using git.

wget http://nodejs.org/dist/node-v0.x.x.tar.gz where x is the vers you want.

next I ran

gunzip node-v0.x.x.tar.gz and also tar -xf node-v0.x.x.tar

then you need to cd into the new dir and run ./configure
then run make
and then finally make install

if like me you want node on a particular tcp in and out port you may need to configure the firewall. If you are using whm/cpanel this is quite easy by adding a port to the tcp_in and tcp_out fields of the firewall config.

I made a dir mkdir /var/node to keep my node app in and to test it I used the basic node tcp example on nodejs.org and connected using mudlet get mudlet

And thats it. So over the next few weeks I will add more posts about the development of the game etc.

Models in node.js and data validation

 Development, node.js  Comments Off on Models in node.js and data validation
Nov 292011
 

So I have been learning about node.js and I have to say that so far I am finding myself warming to it.

I wanted to write a little bit about how I’ve enjoyed using models in a node.js app using the Express web framework.

I am using mongodb for this app and so I am using the mongoose data layer. Mongoose is described as a object modeling tool.

You define a model as follows:


var mongoose = require('mongoose')
, Schema = mongoose.Schema;

/event model/

var Event = new Schema({
title : {type: String, index: true}
, content : {type: String}
, startdate : Date
, enddate : Date
, creator : Schema.ObjectId
, longlat : {lon:Number,lat:Number}
, county : {type:String, index:true}

});

edit
Since writing this piece I have found out that there is a better way of achieving the same result. You can add validators to mongoosejs Schemas as follows:

Schema.path("link").validate(function(value){
if(value.search(/http:\/\/[a-z0-9\-\.]+\.[a-z][a-z][a-z\.]*/gi) !== -1){
return true;
}
return false;
}, "link error");


The path is the path to the field in the schema and the second arg is the type of error which will be thrown.


What I have really liked is the “middleware” options. So you can define methods which will be called at a certain point in the execution; for example pre save.
Here is an example:

Event.pre('save',function(next){

var errors = [];
console.log("I was called first before save");
if(this.title.length < 20) errors[errors.length] = {field:"title",message:"title invalid"}; if(errors.length > 0){
var error = new Error("Invalid Input");
error.errors = errors;
next(error);
}
next();

});

So in the above code next is the next function to be called in the chain which ends with the call back defined after save was called on the model

/some controller method

saveEvent : function(req,res){
var event = new Event();
event.title = req.body.title;
event.save(function(err,suc){
//control is returned here
if(err){ //do something with errors}
else{//succeeded}
});
}

You can define more than one function in your model to be called pre some event in this case the next will refer to the next peice of middleware.

For more info on mongoose you can see here Middle ware in mongoose

© 2012 Craig Brookes Suffusion theme by Sayontan Sinha