Real time online activity monitor example with node.js and WebSocket

Here at New Bamboo, we specialise on Ruby On Rails web development.
However, we started talking more and more about exciting things happening around HTML5 and javascript during morning standup
(where we talk about all the cool things we are working/have discovered) , lunch time and our company hack day.

The latest hot topic is node.js. Some of us went to Full Frontal Javascript Conference and were very excited by the power and potential of node.js which Simon Willison (Django core team) introduced there.
Simon describes node.js as “A toolkit for writing extremely high performance non-blocking event driven network servers in JavaScript”. I highly recommend you to read his blog post, “Node.js is genuinely exciting”

Here, I created an child process to watch “tail” command. This will happen only once when you started node server.

tail.addListener("output", function (data) {

Then, I created an listener to send the output of tail command to http body as new message is written to errorlog. This will keep the connection open per http request.

Keep watching a process activity continuously is not an easy thing to do in normal web app, but it’s almost effortless thanks to node.js non-blocking architecture, and javascript’s event driven pattern.

Try running the script by specifying errorlog you want to watch like below

node tail.js development.log

Open http://localhost:8000. It will show you error messages as they are written to the log file.

However, I wanted to do more, like drawing usage graph and stuff. It doesn’t make sense for me to do all drawing at server side and send the image as it comes, so now it’s time to write some code at client side.

Step 2: Ajax polling

Initially, I tried to do Ajax long polling as you normally do with online chat app, but it did not work as I expected. (You can check out my failed attempt here if you are curious)

I think there are 3 problems applying long polling to a scenario like my app .

Ajax success callback will fire when you receive all the response. It will not fire off if your response never finishes.

Even if you put timeout every 30 sec, the ajax success callback needs to wait for 30 sec, which is far from real time update.

If you shorten the timeout to 1 sec, you will receive constant result, but it's far from real time. In addition, continuous request will hammer your server, and it won’t guarantee that you get result from server every one sec. if there are network latency, you will lose the data during the latency.

Step 3: WebSocket

I need some solution to establish connection between client and server and do something as data arrives to client. Luckily, I had a chance to attend HTML5 communication workshop, and got introduced to one of HTML5 feature called “Web Sockets”

Here is the explanation of HTML5 Websocket from Kaazing, the company which provided the workshop.

The HTML 5 specification introduces the Web Socket interface, which defines a full-duplex communications channel that operates over a single socket and is exposed via a JavaScript interface in HTML 5 compliant browsers. The bi-directional capabilities of Comet and Ajax, unlike Web Sockets, are not native to the browser, and rely on maintaining two connections-one for upstream and one for downstream—in order to stream data to and from the browser. Note, that to support streaming over HTTP, Comet requires a long-lived connection, which is often severed by proxies and firewalls. In addition, few Comet solutions support streaming over HTTP, employing a less performant technique called “long-polling” instead.

Web Sockets account for network hazards such as proxies and firewalls, making streaming possible over any connection, and with the ability to support upstream and downstream communications over a single connection, Web Sockets place less burden on your servers, allowing existing machines to support more than twice the number of concurrent connections.
Simple is Better

I also learnt during the workshop about drastic reduction of network traffic in use of WebSocket.

During making connection with WebSocket, client and server exchange data per frame which is 2 bytes each, compared to 8 kilo bytes of http header when you do continuous polling.
Here is the comparison of 2 scenarios

Within WebSocket supported browser (at this moment Chromium, and OSX version of Chrome only, but don’t go away yet. There is a solution for other browsers,which I will explain later),
all you have to do is something like this (the example from Kaazing’s website)

With this, all you have to do at server side is to define what server returns while the connection is established. Here is the code example from Alexander’s blog to echo whatever you sent from browser. You have to define it under “resources” directory.

At this snippet, I added child process to watch the result of iostat (I just changed my mind by that time to show iostat, rather than tail).
Then, I added an listener inside "handleData" function to parse the result of iodata, construct the result set into hash, then send the response back in JSON format.

Step 5: What else can we do with WebSocket?

In this example, I showed how to stream the output of iostat in real time, but you should be able to stream other stuff , such as XMPP(Extensible Messaging and Presence Protocol, used for Google Talk and Google Wave), and STOMP(Streaming Text Orientated Messaging Protocol, which ActiveMQ uses as protocol). To do them on node.js, you need to implement a logic to handle these protocols on top of TCP. I haven't seen any libraries, but hopefully someone implement them... It’s actually possible to transfer binary data, such as video and audio, but it may not be practical, as Javascript at client side has to encode them.

Step 6: Is this WebSocket future thing?

Many features of HTML5 (Canvas, geo location, offline storage, etc) are already implemented in many of existing browsers, but WebSocket is still a cutting edge. You need to keep an eye on which browser it will start implementing the feature at somewhere like StackOverflow

Does this mean you can forget about WebSocket for another few years? If you are seriously considering WebSocket in enterprise environment (but not with node.js), you might want to consider Kaazing Open Gateway. They are doing pretty good job by automatically detecting Websocket support of your browser, and switch to alternative solutions(Silverlight, Flash Socket and so on). They also support XMPP and STOMP, so if you are interested in displaying real time stock feed, there is already an solution. In fact, their demo page has some interesting real time stock feed as well as resource monitoring, just like I did.

However, I am probably not enterprise enough for their license, and I am more interested in using it with node.js. I found some interesting solution by Hiroshi Ichikawa

And add flash policy file on your machine, or tweak websocket-server-node.js to return policy file (alternatively, if you serve both client side and server side code from same domain/port, you don’t need to worry about cross domain policy at all.), you should be able to use WebSocket on other browsers, as long as flash is supported.

js.io It’s not WebSocket, but a framework to write various network server/clients using multiple protocols (such as TCP and Comet). Also uses node.js

There are new things coming up almost every day. The best way to stay tuned to node.js/websocket is just keep watching twitter search feed

Summary

Here is the recap of what I learnt.

It is extremely easy to write streaming logic in node.js

However, you need a solution at client side to handle the incoming data real time.

Websocket enables you to have continuos communication in significantly less network overhead compared to existing solution.

Websocket is not available in most browsers yet, but there are workarounds.

I hope I was able to share my experiment well and looking forward to hearing about exciting apps/libraries/projects related to the both topics. Also, my understanding about them are less than perfect, so welcome any feedback / corrections / suggestions.